async/awaitとforEach
1987 ワード
async/await
はとても使いやすいですが、Array.forEach()
にはトラップがあります.問題の説明
たとえば、次のコードがあります.
const waitFor = (ms) => new Promise(r => setTimeout(r, ms));
[1, 2, 3].forEach(async (num) => {
await waitFor(1000);
console.log(num);
});
console.log('Done');
コンソールで上記のコードを実行した結果は次の通りです(node.jsバージョン≧13.0.0).
$ node forEach.js
$ Done
$ 1
$ 2
$ 3
もんだいぶんせき
console.log(num)
の結果は最後に出力され、同時に出力される.forEach()
の方法を作成して、何が起こったのかを理解します.Array.prototype.forEach = function (callback) {
//
for (let index = 0; index < this.length; index++) {
// callback ,
callback(this[index], index, this);
}
};
forEach()
のpolyfillインプリメンテーションは、以下を参照してください.MDN-Array.prototype.forEach()
callback
はasync/await
で実行されていないので、Promise
の結果は最後に印刷されないことがわかります.問題を解決する
asyncForEach
の代わりに、自分で書いたforEach
の方法を使用することができます.asyncForEach([1, 2, 3], async (num) => {
await waitFor(50);
console.log(num);
})
console.log('Done');
上のコードを実行すると、次の結果が表示されます.
$ node forEach.js
$ Done
$ 1
$ 2
$ 3
結果はあまり変わらないようですが、
console.log(num)
はすでにasync/await
で実行されており、setTimeout
の効果も見られます.しかし、まだ理想的ではありません.実際には
asyncForEach
がPromise
を返します.async
関数に包まれているので、実行が完了してから最後のDone
を印刷するのを待つことができます.const start = async () => {
await asyncForEach([1, 2, 3], async (num) => {
await waitFor(50);
console.log(num);
});
console.log('Done');
}
start();
再実行すると、正しい結果が表示されます.
$ node forEach.js
$ 1
$ 2
$ 3
$ Done