async/await
について読みましたが、重要な質問があります。最初に古い例を説明して質問のベースを示し、次に正確な質問をします。
誰もがそれを知っています:
console.log('1');
console.log('2');
console.log('3'); // Ex: 123
簡単ですが、以下の場合です。
console.log('1');
setTimeout(()=>{
console.log('2');
},0);
console.log('3'); // Ex: 132
setTimeout
関数はasynchronous
であり、JavaScript
はそこからジャンプし、解決後にその関数を実行するので、2
の後に1
が表示されます。および3
。
しかし、今私はasync/await
を読み、次のような関数を作成しました。
(async function test() {
console.log('1');
await setTimeout(()=>{
console.log('2');
},0);
console.log('3');
})(); // Ex: 132
エクスポートも132
ですが、なぜですか?これが私の質問です。なぜ3
が2
の前に実行されるのですか? async/await
JavaScriptが1
を待ってから、2
を書き込んだ後の3
のために期待しています。なぜ132
?
await
は、渡された値がPromise
の場合にのみ一時停止します。あなたの場合、setTimeout
はNumber
を返すので、awaitはそれを待ちません。
正しいコードは次のとおりです。
async function test() {
console.log('1');
await new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve()
}, 0);
});
console.log('3');
}
setTimeout
はpromiseを返さないためです。 _await x
_は、x
が約束である場合にのみ待機します。 x
が約束でない場合は、await Promise.resolve(x)
があるかのように(事実上)1つにラップされます。つまり、それに続くコードは非同期で実行されますが、できるだけ早く実行されます。*
setTimeout
のpromiseバージョンが必要な場合は、 この質問の回答 を参照してください。しかし、それでも、test
関数はコールバックを使用せず、代わりに、promiseが有効なタイムアウトを待つだけです。
_function later(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}
async function test() {
console.log("1");
await later(10);
console.log("2");
console.log("3");
}
test().catch(e => console.error(e));
console.log("After the call (just to prove it does wait for the timeout after 1 and before 2");
_
*ブラウザでは、同じタスク中にスケジュールされたsetTimeout(..., 0)
の前にあることが保証されます。これは、タスク中にスケジュールされたpromiseコールバックが、そのタスクの終了直後、次のタスクがキューから取得される前に発生するためです(次のタスクがpromiseコールバックの前にスケジュールされていたとしても)。これについての詳細(「マクロタスク」と「マイクロタスク」) この質問の回答 。
await
を返す関数にPromise
することができます。 setTimeout
はPromise
を返しません。したがって、この場合、await
の前に使用されるsetTimeout
には意味がありません。
setTimeout
をPromiseにラップし、setTimeout
関数でresolveを呼び出すことができます。
(async function test() {
console.log('1');
await new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve(); // also can pass a parameter here to get it via await.
},0);
});
console.log('3');
})();