重新理解 JavaScript 非同步運作流程

Andy Chen
Andy的技術分享blog
5 min readMar 25, 2021

--

前言

原本筆者一直以為自己對於 JavaScript 的非同步運作非常了解,直到我看了一個題目才發現原來自己只是略懂皮毛而已,於是決定來寫個文章加深一下自己的觀念畢竟也好久沒有寫文章了😂

其實筆者以前就寫過非同步與同步的文章,如果有不懂非同步基本觀念的讀者可以先看以前筆者寫過的文章補充一下基本知識~

小試身手

首先先來個小題目來小試身手一下,讀者可以猜一下輸出順序是多少:

相信懂一點 JavaScript 非同步觀念的讀者馬上就可以猜出輸出順序是 Hello 再來是 Bye 最後才是 Hello Andy ,這是因為 JavaScript 會優先執行同步的程式碼最後才去執行非同步的程式碼,拜 event loop 所賜我們就可以知道非同步的程式碼什麼時候會執行完畢,因為 event loop 會不斷的去檢查目前的 callback stack 是不是還有未執行的程式碼。

接下來讀者再來猜猜看輸出順序是多少:

按照非同步的邏輯輸出順序應該是 Hello -> Bye -> Hello Andy -> Hello Promise ,沒錯筆者一開始也以為輸出順序是這樣但實際丟到瀏覽器的 console 中執行卻發現順序是這樣:

microtask and marcotask

這是在搞我吧!同一套邏輯竟然會產出不一樣的結果,後來才知道原來是自己見識真的太淺薄了,沒有深入去瞭解 JavaScript 的非同步運作原理才會這樣。

其實在 JavaScript 的非同步中還包含了 microtask 以及 marcotask 這兩種不同的 task,這兩種 task 在 event loop 中的執行順序也不同,接下來就來仔細講講這兩個 task 的差別吧!

marcotask

在開始講 macrotask 之前要先來提提 web 原生的非同步 API,例如 setTimeoutsetIntervalsetImmediate 等等。

這些 API 在 event queue 中被稱之為 marcotask,當 marcotask 執行完畢後瀏覽器就會進行渲染,換句話說 marcotask 在 event queue 中永遠都是最後執行的。

而 marcotask 都是 task by task 執行的,一個 task 執行完才執行下一個 task,可能有點抽象因為程式碼本來就是一條一條執行的,所以這邊筆者舉一個例子:

根據 microtask 會比 marcotask 優先執行的原理,所以會猜出上面的順序應該是 Second Promise -> First Promise -> First Hello -> Second Hello 吧!但結果其實是這樣:

microtask and marcotask

這代表著即便我 marcotask 中有 microtask 在一樣不會優先執行,因為 marcotask 是一條執行完後才去執行下一條,不像 microtask 是一起輸出。

microtask

microtask 主要是由 Promise 組成,我們都知道非同步的函式最後都會被丟回去 callback stack 中執行,而 Promise 中負責執行的 callback 就是 then 以及 catch 的 callback 啦!

為什麼 microstack 會比 marcotask 還要優先執行呢?因為 microtask 在執行完畢後並不會馬上進行畫面渲染,而網頁渲染永遠都是最後一個步驟,而觸發這個條件的就是 macrotask,但其實比較好的說法是 microtask 會穿插在各個 marcotask 中間執行,相信看了下方的圖片後就更了解 microtask 以及 marcotask 的執行順序。

event loop

看了上面的圖相信讀者也能夠理解為什麼 microtask 可以一起輸出,而 marcotask 只能 task by task 的輸出了,當 microtask 的 queue 都清空後,剩下待執行的 task 就只剩 marcotask 了,所以最後才會決定是否要讓網頁渲染了。

小結

今天介紹了更深入的 JavaScript 非同步觀念,也算是幫助自己更了解非同步的運行原理,每次在深入研究 JavaScript 的原理總是可以讓自己發現一些小驚喜,我想這也是為什麼 JavaScript 可以讓筆者那麼喜歡專研的原因吧XD

Reference

--

--

Andy Chen
Andy的技術分享blog

嗨嗨我是Andy,用嘴巴工作的工程師😂,喜歡學習不同領域的內容,專長為網頁開發,歡迎大家跟我聊技術~