1. 程式人生 > >promise與setTimeout的執行順序問題

promise與setTimeout的執行順序問題

有一次在面試題中有做到promise與setTimeout的執行順序,當時有點懵,執行順序還是弄錯了一點點,這裡記錄下

1.輸出

setTimeout(function() {
    console.log(111)
}, 0);
setTimeout(function() {
    console.log(333)
}, 1000);
new Promise(function(resolve){
    console.log(444);
    resolve();
    console.log(555);
}).then(function(){
    console.log(666);
});
console.log(777);
async function test1() {
    console.log("test1");
    await test2();
    console.log("test1 last");
}
async function test2() {
    console.log("test2");
}
test1();
  • 輸出結果

2.個人理解

  • 首先執行同步程式碼,然後以事件輪詢的方式執行非同步程式碼
  • promise中的非同步體現在.then()和.catch()中
  • 而promise中的function裡的是同步程式碼
  • 上面的程式碼是先執行promise裡的同步程式碼,然後執行腳本里本身的同步程式碼
  • async無論方法是同步還是非同步都可以用async關鍵字來進行標識
  • 因為用async標識只是顯示錶明在該方法內,可能會用到await關鍵字使其變為非同步方法,而且將該非同步方法進行了明確的劃分,只有用了await關鍵字時才是非同步操作,其餘一併為同步操作
  • 同 Generator 函式一樣,async 函式返回一個 Promise 物件,可以使用 then 方法添加回調函式
  • 當函式執行的時候,一旦遇到 await 就會先返回,等到觸發的非同步操作完成,再接著執行函式體內後面的語句
  • await 命令後面的 Promise 物件,執行結果可能是 rejected,所以最好把 await 命令放在 try...catch 程式碼塊中

3.其他

  • 在網上還找到了一些資料
參考了這篇文章的一些內容  參考文章
setImmediate(function(){
    console.log(1);
},0);
setTimeout(function(){
    console.log(2);
},0);
new Promise(function(resolve){
    console.log(3);
    resolve();
    console.log(4);
}).then(function(){
    console.log(5);
});
console.log(6);
process.nextTick(function(){
    console.log(7);
});
console.log(8);
  • 輸出結果: 3 4 6 8 7 5 2 1
macro-task: script (整體程式碼),setTimeout, setInterval, setImmediate, I/O, UI rendering. 
micro-task: process.nextTick, Promise(原生),Object.observe,MutationObserver
  • 第一步. script整體程式碼被執行,執行過程為
建立setImmediate macro-task
建立setTimeout macro-task
建立micro-task Promise.then 的回撥,並執行script console.log(3); resolve(); console.log(4); 此時輸出3和4,雖然resolve呼叫了,執行了但是整體程式碼還沒執行完,無法進入Promise.then 流程。
console.log(6)輸出6
process.nextTick 建立micro-task
console.log(8) 輸出8 
  • 第一個過程過後,已經輸出了3 4 6 8
  • 第二步. 由於其他micro-task 的 優先順序高於macro-task。
  • 此時micro-task 中有兩個任務按照優先順序process.nextTick 高於 Promise,所以先輸出7,再輸出5
  • 第三步,micro-task 任務列表已經執行完畢,家下來執行macro-task. 由於setTimeout的優先順序高於setIImmediate,所以先輸出2,再輸出1。

優先順序: promise.Trick()>promise的回撥>setTimeout>setImmediate