iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
Modern Web

前端藏寶圖系列 第 16

同步與非同步

剛開始學習JavaScript的時候,很單純的認為所有程式碼是逐行執行的,就像看書不都是ㄧ行一行閱讀嗎?直到踩到callback function 的地雷才意識到必須瞭解 JavaScript 具有非同步特性。

為什麼需要非同步?

JavaScript 是單線程語言,代表程式碼只能一行一行執行,若上一行的程式碼卡住,下一行的程式碼就無法執行。

但現代網頁的互動特性有些要等待使用者點擊,有些時候則是需要載入第三方提供的影像等等,若是維持同步方式處理的話,當等待資源的時間過長就會造成畫面卡住的現象,因此,JavaScript的設計者將所有要執行的任務分成兩種:

  1. 同步 (Synchronous)
  2. 非同步(Asynchronous)

哪些是非同步?

  • setTimeout: 等待幾秒後再執行
  • addEventListener: 等待觸發的事件才執行
  • fetch: 發送請求,需要等待回應

JavaScript 如何做到非同步


圖片來源:sessionstack

JavaScript 執行環境中有一個叫做 Call Stack 的地方,負責存放要執行的函式。

可以把 Call Stack 想成辦公桌上放待辦事項的地方,每天上班時,可能需要先開會,然後會議上老闆交派許多任務,回到辦公室後得將任務一一分類,有些任務可能需要經過其他部門審核,有些可能需要詢問外部廠商,這些無法由你自己立刻處理的任務,就會給相關部門處理,完成後再放到一個叫做Callback Queue的位置。

而 Event Loop 就像一位積極的秘書,會不斷觀察辦公桌上的代辦事項完成了沒,當辦公桌上沒有任何任務後,就會把放在 Callback Queue 中的任務放到辦公桌上讓你接手完成。

回到程式語言來談,代表當程式碼是瀏覽器提供的API時,就會丟到 Web APIs中。
像是setTimeout就會在到達設定的秒數後被放入CallBack Queue中等待,等到 Call Stack 清空後,Event Loop 就會把 setTimeout 放入Call Stack 並立即執行其中的程式碼。

stack 按照後進先出(LIFO, Last In First Out)的原理運作
quene 運作方式則是先進先出(FIFO, First-In-First-Out)

console.log("決定鐵人賽主題");

setTimeout(() => {
  console.log("先找一下資料");
}, 0);

setTimeout(() => {
  console.log("開始寫鐵人賽文章");
}, 0);

console.log("完成鐵人賽文章了!");

深入認識了 Event loop 後就可以理解為什麼 setTimeout 明明設定了0秒,為什麼還是不會依序印出:

決定鐵人賽主題 -> 先找一下資料 -> 開始寫鐵人賽文章 -> 完成鐵人賽文章了!

只要記得所有非同步的事件都會先進到 Callback Queue 中,等待 Call Stack 中的任務執行完畢,才會輪到非同步的程式碼執行。

參考資料:
Concurrency model and the event loop
所以說event loop到底是什麼玩意兒?
loupe
理解 JavaScript 中的事件循環、堆疊、佇列和併發模式


上一篇
網頁儲存區 - localStorage & sessionStorage
下一篇
Promise
系列文
前端藏寶圖30

尚未有邦友留言

立即登入留言