前提知識
・Microtask queue、Macrotask queueー非同期処理が格納されるキュー。setTimeoutはMacrotask、Promiseのコールバック関数はMicrotask queueである。
・処理の優先順位は、コールスタックに入れられた関数>Microtask queue>Macrotask queue。コールスタックが空になったとき、Microtask queueが呼ばれ、その両方が空になったとき、Macrotask queueが呼ばれる。
・要するに、大まかに言うと、処理の順番は、「非同期じゃないコード」→「Microtask queueに入れられた関数(キュー入れられた順)」→「Macrotask queueに入れられた関数(キューに入れられた順)」である。(途中で優先度の高い処理が追加されると前に戻る)
仕様① awaitが読み込まれたときの挙動
・awaitの行に差し掛かった時、awaitの右に書かれた処理を実行した後、async関数を中断し、async関数を「Microtask queue」に入れる。
以下はコード例。
async function hello()
{
console.log("hello")
var b = await 1
console.log("hello"+b)
}
console.log("start")
hello()
console.log("end")
上を実行すると、start→hello→end→hello1の順でログが出力される。
仕様② async関数の返り値
・async関数の返り値はPromiseオブジェクト。
・async内の処理が終わっていない場合は、stateが「Pending」であるPromiseを返す。
・async内の処理が終わっている場合は、stateが「Fulfilled」であるPromiseを返す。
・returnは関数の返り値とはならない。返り値は常にPromiseオブジェクトで、その中にreturnの結果が保存される。
以下はコード例。
async function hello()
{
var b = await 1
console.log("resume!")
return b
}
a = hello()
console.log(a)
window.setTimeout(() => {
console.log(a)
}, 1000)
上を実行すると、stateが「Pending」であるPromiseオブジェクトが出力された後、「resume!」が出力され、1秒後にstateが「Fulfilled」であるPromiseオブジェクトが出力される。
仕様③ 実行順序に気を付ける
・実は、仕様②で書いたコードのsetTimeoutの秒数を0にしても、結果は同じです。
・何故なら、「Microtask queue」→「Macrotask queue」の順に実行されるからです。