js的單線程事件循環機制(event loop)的典型例子

例1、以下代碼輸出結果

setTimeout(function() { 
  console.log(1)//第二個宏任務
}, 0);
new Promise(function executor(resolve) { 
  console.log(2);//同步執行
  for( var i=0 ; i<10000 ; i++ ) {
    i == 9999 && resolve();
  }
  console.log(3);//同步執行
}).then(function() {
  console.log(4); //微任務
});
console.log(5); //第一個宏任務
//2,3,5,4,1
  1. 宏任務

setTimeoutsetIntervalsetImmediate, I/O,promise中的executor,script;

  1. 微任務

原生PromisePromise.then,(有些實現的promise將then方法放到了宏任務中),MutationObserver, MessageChannel,process.nextTick

  • 出現async/await不要慌,記住async正常執行,await後面的函數相當於promise.then,是一個微任務
  • 特別的:setImmediate比setTimeout先執行.
  • process.nextTick和Promise的回調函數,追加在本輪循環,即同步任務一旦執行完成,就開始執行它們,process.nextTick優先級高於Promise.then

執行代碼過程:先執行宏任務,清空微任務再執行下一個宏任務

例2、以下代碼會輸出什麼?

      setTimeout(function () {
        console.log(1)
      }, 0)
      setTimeout(function () {
        console.log('999999')
      }, 10)
      let a = function () {
        console.log(2)
        return new Promise(function (resolve) {
          resolve(3)
        }).then(function (data) {
          console.log(data)
        })
      }
      async function fun () {
        let c = await a()
        new Promise(function (resolve) {
          console.log(4)
          for (var i = 0; i < 10000; i++) {
            i === 9999 && resolve()
          }
          console.log(5)
        }).then(function (data) {
          console.log(6)
        })
      }
      fun()
      console.log(7);

2,7,3,4,5,6,1,9999

async和await,promise的代碼是同步執行
then中的代碼是微任務
serTimeout異步執行,

  • 總結
    當前宏任務執行完了,清空微任務再開始下一個宏任務。
    setTimeout是一個宏任務,promise裏面的代碼是同步執行的,then中的代碼是一個微任務。當前宏任務執行完了,就執行微任務裏面的,微任務清空後,執行下一個宏任務即setsetTimeout第一個參數的內容

例3、求輸出結果

  fetch('...').then(res=>{
    console.log(1)
  })
  console.log(2);
  function getValue () {
    console.log(3)
    return new Promise(resolve => {
      console.log(4)
      fetch('...').then(res=>{
        console.log(5)
        resolve(res)
      })
    })
  }
  getValue().then(res=>{
    console.log(6);
  })
  //fetch('...') 表示http請求
  //2,3,4,1,5,6

例4

  Promise.resolve().then(()=>{
    console.log('1')
    setTimeout(()=>{
      console.log('2')
    },0)
  })

  setTimeout(()=>{
    console.log('3')
    Promise.resolve().then(()=>{
      console.log('4')
    })
  },0)
  //1,3,4,2

個人理解:

  • 執行1的時候同時將宏任務3添加到執行隊列中,
  • 再將宏任務2添加到執行隊列中,
  • 將宏任務3從執行隊列中取出到執行棧中執行,執行3後,會去執行其微任務4,
  • 任務3執行完畢後,最後再將宏任務2中取出到執行棧中執行

宏任務1,執行完畢後再去執行宏任務2,當宏任務1中如果有Promise這種微任務,則會先執行微任務,再執行宏任務2;
網上優秀的講解
這個講解也不錯

  • 上面的理解,理解通透了其實也就差不多了,以下是進化版本

例五 promise的回調地獄

https://juejin.im/post/5c9a43175188252d876e5903

//1-1、求結果
new Promise((resolve,reject)=>{
    console.log("1")
    resolve()
}).then(()=>{
    console.log("2")
    new Promise((resolve,reject)=>{
        console.log("3")
        resolve()
    }).then(()=>{
        console.log("4")
    }).then(()=>{
        console.log("5")
    })
}).then(()=>{
    console.log("6")
})
//1,2,3,4,6,5

//1-2 改進,求結果
new Promise((resolve,reject)=>{
    console.log("1")
    resolve()
}).then(()=>{
    console.log("2")
    return new Promise((resolve,reject)=>{
        console.log("3")
        resolve()
    }).then(()=>{
        console.log("4")
    }).then(()=>{
        console.log("5")
    })
}).then(()=>{
    console.log("6")
})
//1,2,3,4,5,6
//[解析]用了return後這裏Promise的第二個then相當於是掛在新Promise的最後一個then的返回值上。
//因爲return是同步任務,所以比6先執行

//2、理解這個
new Promise((resolve,reject)=>{
  console.log("1")
  resolve()
}).then(()=>{
  console.log("2")
}).then(()=>{
  console.log("3")
})
new Promise((resolve,reject)=>{
  console.log("4")
  resolve()
}).then(()=>{
  console.log("5")
}).then(()=>{
  console.log("6")
})
new Promise((resolve,reject)=>{
  console.log("7")
  resolve()
}).then(()=>{
  console.log("8")
}).then(()=>{
  console.log("9")
})
//147258369
//平行世界的then先進先出

// 3、改進-更復雜的
new Promise((resolve,reject)=>{
  console.log("1")
  resolve()
}).then(()=>{
  console.log("2")
  new Promise((resolve,reject)=>{
    console.log("3")
    resolve()
  }).then(()=>{
    console.log("4")
  }).then(()=>{
    console.log("5")
  })
}).then(()=>{
  console.log("6")
})
new Promise((resolve,reject)=>{
  console.log("7")
  resolve()
}).then(()=>{
  console.log("8")
}).then(()=>{
  console.log("9")
})
//1,7,2,3,8,4,6,9,5

new Promise((resolve, reject) => {
  console.log("1")
  resolve()
}).then(() => {
  console.log("2")
  setTimeout(function(){
    console.log("3")
  },0)
  new Promise((resolve, reject) => {
    console.log("4")
    resolve()
  }).then(() => {
    console.log("5")
  }).then(() => {
    console.log("6")
  }).then(() => {
    console.log("7")
  })
}).then(() => {
  console.log("8")
}).then(() => {
  console.log("9")
})
new Promise((resolve, reject) => {
  console.log("10")
  resolve()
}).then(() => {
  console.log("11")
}).then(()=>{
  console.log(12)
}).then(() => {
  console.log("13")
})
//錯誤:1,10,2,4,11,8,5,12,9,6,13,7,3
//1,10,2,4,11,5,8,12,6,9,13,7,3

例6 async和await

async function async1() {
    console.log("1");
    await  async2();
    console.log("2");
}
async  function async2() {
    console.log( '3');
}
console.log("4");
setTimeout(function () {
    console.log("5");
});
async1()
new Promise(function (resolve) {
    console.log("6");
    resolve();
}).then(function () {
    console.log("7");
});
setImmediate(()=>{
    console.log("8")
})
console.log('9');//4,1,3,6,9,2,7,8,5

例7 async和await

async function async1() {
  console.log("1");
  await  async2();
  console.log("2");
}
async  function async2() {
  console.log( '3');
}
// 用於test的promise,看看await究竟在何時執行
new Promise(function (resolve) {
  console.log("4");
  resolve();
}).then(function () {
  console.log("5");
}).then(function () {
  console.log("6");
}).then(function () {
  console.log("7");
}).then(function () {
  console.log("8");
});
async1();
// 4,1,3,5,2,6,7,8
async function async1() {
    console.log('1');
    await async2();
    console.log('2');
}
async function async2() {
    console.log('3');
}
console.log('4');
setTimeout(function() {
    console.log('5');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('6');
    resolve();
}).then(function() {
    console.log('7');
});
console.log('8');
//錯誤答案 4,1,6,8,3,2,7,5
//原因:await後面的代碼是microtask 講解鏈接: https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/7
// 4,1,3,6,8,2,7,5

例8、綜合案例

async function async1(){
  console.log('1')
  await async2()
  console.log('2')
}
async function async2(){
  console.log('3')
}
console.log('4')
setTimeout(function(){
  console.log('5')
},0)
setTimeout(function(){
  console.log('6')
},3)
setImmediate(() => console.log('7'));
process.nextTick(() => console.log('8'));
async1();
new Promise(function(resolve){
  console.log('9')
  resolve();
  console.log('10')
}).then(function(){
  console.log('11')
})
console.log('12')
//  錯誤答案:4,1,3,9,10,12,2,7,8,11,5,6
//  正確答案:4,1,3,9,10,12,8,2,11,5,7,6

推薦文章,講解更詳細

https://juejin.im/post/5c9a43175188252d876e5903

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章