跳至內容
Astera Technology

同步程式先跑完,微任務才接住處理

Promise 已完成,回呼仍要等同步程式跑完。

下載完整個案資料及參考答案 ↓

先追這段程式

先放 start,排入 Promise 回呼和 queueMicrotask,然後同步放 end。最後再排一個回呼印出記錄。

完整原始程式
const trace=['start'];
Promise.resolve().then(()=>trace.push('promise'));
queueMicrotask(()=>trace.push('microtask'));
trace.push('end');
Promise.resolve().then(()=>console.log(JSON.stringify(trace)));
確實的 console 輸出
["start","end","promise","microtask"]
值與執行位置
執行位置加入值當時記錄
同步程式start, end["start","end"]
首個排隊回呼promise["start","end","promise"]
明確微任務microtask["start","end","promise","microtask"]

結果為何如此

這段同步程式會先跑完;本例 Promise 回呼先入隊,明確微任務隨後,列印回呼最後。不涉及實際毫秒,也不推論其他工作或不同執行環境的整體排程。

比較另一種寫法

Promise 已 fulfilled,也不會在 .then 當下同步執行。即時讀旗標是假,後面的回呼才讀到真。

另開的有限例子
let ran=false;Promise.resolve().then(()=>{ran=true;});const immediate=ran;
Promise.resolve().then(()=>console.log(JSON.stringify({immediate,later:ran})));
另一寫法的輸出
{"immediate":false,"later":true}

試清邊界

先排 queueMicrotask,再排 Promise 回呼,次序怎樣變?

查看參考答案

兩個排隊標記調換;本程式的 start、end 仍先於它們。

重新建立的邊界例子
const trace=['start'];queueMicrotask(()=>trace.push('microtask'));Promise.resolve().then(()=>trace.push('promise'));trace.push('end');
Promise.resolve().then(()=>console.log(JSON.stringify(trace)));
邊界例子的輸出
["start","end","microtask","promise"]

原始例子檔案