EventLoop

qq_39288218發表於2020-11-09

毋庸置疑,大家都很瞭解js是一門單執行緒語言,這也就說明JS無法進行多執行緒,但是JS中非同步的功能完全可以模擬多執行緒,而且效果還槓槓滴。當然,如果想完全理解非同步,首先要了解JS的執行核心——事件環(Event Loop),下面分兩部分理解事件環:

一:瀏覽器中的事件環(Event Loop)

  1. 為了能更好的理解JS在瀏覽器中的任務佇列和事件迴圈,請看下圖:

EventLoop

  • eventLoop 是由JS的宿主環境(瀏覽器)來實現的;
  • 事件迴圈可以簡單的描述為以下四個步驟:

1. 函式入棧,當Stack中執行到非同步任務的時候,就將他丟給WebAPIs,接著執行同步任務,直到Stack為空;
2. 此期間WebAPIs完成這個事件,把回撥函式放入佇列中等待執行(微任務放到微任務佇列,巨集任務放到巨集任務佇列)
3. 執行棧為空時,Event Loop把微任務佇列執行清空;
4. 微任務佇列清空後,進入巨集任務佇列,取佇列的第一項任務放入Stack(棧)中執行,回到第1步。

複製程式碼
  1. 認識瀏覽器中的任務源(task):
  • 微任務:then 、messageChannel 、mutationObersve
  • 巨集任務:setTimeout、setInterval、setTmmediate(只相容ie)
  1. 下面實現一個小例子:

console.log(1);
console.log(2);
setTimeout(function () {
  console.log('setTimeout1');
  Promise.resolve().then(function () {
    console.log('promise');
  });
});
setTimeout(function () {
  console.log('setTimeout2');
});

複製程式碼

列印結果:

1
2
setTimeout1

promise

setTimeout2

二:Node 環境中的事件環(Event Loop)

  1. 為了能更好的理解JS在Node環境中的任務佇列和事件迴圈,請看下圖:

EventLoop

  • 圖雖然有些亂,但是我們只需關心timers計時器階段和poll輪詢階段,check檢查階段即可,clons關閉階段以及微任務佇列即可。

  • Node 環境中微任務是插縫執行,(如果執行巨集任務的時候發現了微任務, 不會像瀏覽器一樣執行了,而是將為微任務放到微任務佇列中,等待整個巨集 任務佇列執行完畢或者達到執行上線後,下一個階段開始的時候先執行 完微任務佇列中的任務)。

  1. 認識Node中的任務源(task):
  • 微任務: then 、nextTick 、 messageChannel 、mutationObersve
  • 巨集任務:setTimeout 、setInterval 、setImmediate 、io檔案操作
  1. 例一:timeout、immediate 兩個誰先執行不一定 取決於node的執行時間。
setTimeout(function () {
    console.log('setTimeout1');
})
setImmediate(function () {
    console.log('setImmediate2');
});
複製程式碼
列印結果有兩種:
  • 1) setTimeout1 setImmediate2
  • 2) setImmediate2 setTimeout1
  1. 例二: 如果i/o檔案操作以後就會先執行setImmediate,因為setImmediate在i/o檔案操作後面的那個階段執行,執行完setImmediate會在下一個階段的時候再執行setTimeout (timers 計時器執行階段)
let fs = require('fs');
fs.readFile('1.log', function () {
  console.log('fs');
  setTimeout(function () {
    console.log('timeout');
  });
  setImmediate(function () {
    console.log('mmiediate');
  });
});

複製程式碼
列印順序結果
  • fs 、 miediate、 timeout
  1. 例三: 微任務中nextTIck 會比then先執行。

Promise.resolve().then(function () {
  console.log('then2'):
});
process.nextTick(function () {
  console.log('nextTick1');
});


複製程式碼
列印順序結果
  • nextTick1 then2
  1. 例四: 微任務會優先與i\o檔案操作執行。
let fs = require('fs');
fs.readFile('./1/log',function(){
    console.log('fs')
})
process.nextTick(function(){
    console.log('text2');
})

複製程式碼
列印執行結果
  • text2 fs

好了,今天就到這,如有錯誤,請下方留言。作為碼農一枚,最大的願望和最偉大的理想是,大寶天天見,bug死生不復相見,相忘於江湖,恩怨一筆消失!!!

相關文章