配列でforEachループを実行し、promiseを返す2つの呼び出しを行っています。this.options
などのオブジェクトにデータを入力し、それを使って他の処理を行います。現在、次のコードサンプルを使用して、最初にthen関数を取得すると、非同期の問題が発生します。
$.when.apply($, someArray.map(function(item) {
return $.ajax({...}).then(function(data){...});
})).then(function() {
// all ajax calls done now
});
これは以下の作業コードですが、応答の.then
で結果の関数を呼び出すため、配列の最初の要素に対してのみ機能します。配列のすべての要素に対して最初にすべてのフェッチを実行してから、結果の関数を呼び出して何かを実行したいと思います。
array.forEach(function(element) {
return developer.getResources(element)
.then((data) = > {
name = data.items[0];
return developer.getResourceContent(element, file);
})
.then((response) = > {
fileContent = atob(response.content);
self.files.Push({
fileName: fileName,
fileType: fileType,
content: fileContent
});
self.resultingFunction(self.files)
}).catch ((error) = > {
console.log('Error: ', error);
})
});
ForEachループが完了した後、self.files
オブジェクトに値を設定し、ファイルオブジェクトで結果の関数を呼び出すにはどうすればよいですか?
Promise.all()
はここで役立ちます:
var promises = [];
array.forEach(function(element) {
promises.Push(
developer.getResources(element)
.then((data) = > {
name = data.items[0];
return developer.getResourceContent(element, file);
})
.then((response) = > {
fileContent = atob(response.content);
self.files.Push({
fileName: fileName,
fileType: fileType,
content: fileContent
});
}).catch ((error) = > {
console.log('Error: ', error);
})
);
});
Promise.all(promises).then(() =>
self.resultingFunction(self.files)
);
これにより、各アイテムのAJAX呼び出しが開始され、呼び出しが完了するとself.files
に各呼び出しの結果が追加され、すべての呼び出しが完了した後にself.resultingFunction()
が呼び出されます。
編集: Yury Tarabankoの提案に基づいて簡略化。
上記の承認されたソリューションのわずかなバリエーションは次のとおりです。
var promises = array.map(function(element) {
return developer.getResources(element)
.then((data) = > {
name = data.items[0];
return developer.getResourceContent(element, file);
})
.then((response) = > {
fileContent = atob(response.content);
self.files.Push({
fileName: fileName,
fileType: fileType,
content: fileContent
});
}).catch ((error) = > {
console.log('Error: ', error);
})
});
Promise.all(promises).then(() =>
self.resultingFunction(self.files)
);
Array.map
の代わりにArray.forEach
を使用しました。つまり、最初に空の配列を作成する必要はなく、既存の配列を再利用するだけです。
優れたヒントについては、 同様の質問に対するこの回答 をご覧ください。そこで提供されているソリューションでは、Array#reduce()
を使用するのではなく、Promise.all()
を使用して、作業を行う前にすべてのPromiseを蓄積する必要がありません。
次のコードは、Promiseを使用した同期の簡単な理解です。
let numArr = [1,2,3,4,5];
let nums=[];
let promiseList = new Promise(function(resolve,reject){
setTimeout(()=>{
numArr.forEach((val)=>{
nums.Push(val);
});
resolve(nums);
},5000)
})
Promise.all([promiseList]).then((arrList)=>{
arrList.forEach((array)=>{
console.log("Array return from promiseList object ",array);
})
});
上記の例では、配列numsを5秒間保持します。また、リリース後にコンソールに印刷されます。