1. 程式人生 > 實用技巧 >18 JS的事件迴圈,以及微任務和巨集任務。

18 JS的事件迴圈,以及微任務和巨集任務。

js執行機制:eventloop(事件迴圈),看了很多部落格的講解,我也想自己總結一些這個知識點。

JavaScript的事件分為同步任務和非同步任務

首先第一點,js永遠是單執行緒的,以後也是。

使用單執行緒原因:如果多執行緒,一個執行緒刪除元素,一個執行緒修改元素會造成混亂。

使用單執行緒問題:如果一個任務等待的時間非常久,在這中間會有cpu閒置,1會浪費時間,2會浪費資源。

解決辦法:同步和非同步。

同步任務:主執行緒執行的任務。

非同步任務:不進入主執行緒,而是進入任務佇列,任務佇列通知主執行緒,某個可以執行了,就可以執行。

(1)所有同步任務都在主執行緒上執行(console.log(),for迴圈,new Process裡面),形成一個執行棧(execution context stack)。

(2)主執行緒之外,還存在一個"任務佇列"(task queue)。只要非同步任務有了執行結果,就在"任務佇列"之中放置一個事件。

(3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務佇列",看看裡面有哪些事件。那些對應的非同步任務,於是結束等待狀態,進入執行棧,開始執行。

"任務佇列":除了IO裝置的事件以外,還包括一些使用者產生的事件(比如滑鼠點選、頁面滾動等等)。只要指定過回撥函式,這些事件發生時就會進入"任務佇列",等待主執行緒讀取。

"回撥函式"(callback):就是那些會被主執行緒掛起來的程式碼。非同步任務必須指定回撥函式,當主執行緒開始執行非同步任務,就是執行對應的回撥函式。

JavaScript的任務分為微任務(Microtasks)和巨集任務(task)

0 涉及到的資料結構有什麼?

資料結構:1stack 執行棧。 2 巨集任務佇列。3 微任務佇列。

1 執行規則是什麼?

  答:執行規則:

  1 第一個巨集任務入棧執行,遇到巨集任務放在巨集任務佇列裡面,遇到微任務放在當前微任務佇列裡面,遇到同步程式碼放在棧裡面執行。(注意放的是回撥函式!)

  2 第一個巨集任務執行完,會找到微任務佇列,給微任務佇列說,該你執行了,微任務佇列把自己佇列裡面的任務全部執行完。

  3微任務佇列執行結束。如果還有巨集任務,就繼續執行巨集任務回到1。沒有的話就結束。

2 微任務巨集任務都有誰啊?

1巨集任務(macrotask): 1整個程式碼(scirpt),2定時器(setTimeout ,setImmediate),3事件繫結setInterval,4ajax,5回撥函式,6Node中fs可以進行非同步的I/O操作

2 微任務(microtask):promise.nextTick,promise.then(), async await。

3 直接執行的有:console.log(),new Process裡面的。

3 都是非同步程式碼為什麼還要區分巨集任務,微任務啊?如何區分巨集任務和微任務呢?劃分的標準是什麼?

在ES3以及以前的版本中,JavaScript本身沒有發起非同步請求的能力,也就沒有微任務的存在。在ES5之後,JavaScript引入了Promise,這樣,不需要瀏覽器,JavaScript引擎自身也能夠發起非同步任務了。

兩者區別為:巨集任務是由宿主發起的,而微任務由JavaScript自身發起。

巨集任務(macrotask)微任務(microtask)
誰發起的 宿主(Node、瀏覽器) JS引擎
具體事件 1. script (可以理解為外層同步程式碼)
2. setTimeout/setInterval
3. UI rendering/UI事件
4. postMessage,MessageChannel
5. setImmediate,I/O(Node.js)
1. Promise
2. MutaionObserver
3. Object.observe(已廢棄;Proxy物件替代)
4. process.nextTick(Node.js)
誰先執行 後執行 先執行
會觸發新一輪Tick嗎 不會

巨集任務和微任務的一句話總結:

  • 巨集任務 Macrotasks就是參與了事件迴圈的非同步任務。
  • 巨集任務 Macrotasks就是不參與事件迴圈的非同步任務。

巨集任務本質:參與了事件迴圈的任務。

回到 Chromium 中,需要處理的訊息主要分成了三類:

  • Chromium 自定義訊息
  • Socket 或者檔案等 IO 訊息
  • UI 相關的訊息

1. 與平臺無關的訊息,例如 setTimeout 的定時器就是屬於這個

2.Chromium 的 IO 操作是基於 libevent 實現,它本身也是一個事件驅動的庫

3.UI 相關的其實屬於 blink 渲染引擎過來的訊息,例如各種 DOM 的事件

其實與 JavaScript 的引擎無關,都是在Chromium實現的。

微任務本質:直接在 Javascript 引擎中的執行的,沒有參與事件迴圈的任務。

  1. 是個記憶體回收的清理任務,使用過 Java 的童鞋應該都很熟悉,只是在 JavaScript 這是V8內部呼叫的
  2. 就是普通的回撥,MutationObserver 也是這一類
  3. Callable
  4. 包括 Fullfiled 和 Rejected 也就是 Promise 的完成和失敗
  5. Thenable 物件的處理任務

巨集任務,微任務的優先順序

promise是在當前指令碼程式碼執行完後,立刻執行的,它並沒有參與事件迴圈,所以它的優先順序是高於setTimeout。這也就是為什麼先執行微任務的優先佇列。

3 為什麼整個程式碼(scirpt)在巨集任務裡面?

答:因為一開始需要一個執行機制啊,而且先把所有的同步程式碼執行完,非同步程式碼放入佇列。所以優先級別最高!

建議先看視訊(b站):https://www.bilibili.com/video/BV12Z4y1p7Zd?from=search&seid=15652075497796620445

https://www.bilibili.com/video/BV1Hp4y1Y7h7?from=search&seid=15652075497796620445

建議再看圖文版(知乎):https://zhuanlan.zhihu.com/p/26238030

詳解巨集任務和微任務(部落格園):https://www.cnblogs.com/mfyngu/p/11747533.html

掘金的兩個大佬:

https://juejin.cn/post/6903338967656366094

https://juejin.cn/post/6844903512845860872#heading-2

csdn:

https://blog.csdn.net/xiaojinguniang/article/details/82985471

https://blog.csdn.net/qq_40323256/article/details/104553150

學後練習:

https://blog.csdn.net/weixin_42420703/article/details/82790942

三個大佬的補充,我還沒有看完:

sf:https://segmentfault.com/a/1190000014940904