iT邦幫忙

2021 iThome 鐵人賽

DAY 5
0
Modern Web

網頁前後端寶石庫-礦坑補完計畫系列 第 5

Day 05 JavaScript 同步(Sync) vs 非同步(Async)處理

  • 分享至 

  • xImage
  •  

筆者一開始看到這兩個詞的時候充滿著黑人問號???
同步不是應該表示可以同時處理多件事,
而非同步不是應該表示一次只能處理一件事嗎?
怎麼實際上跟我原本的理解完全相反!!!

同步 Synchronous

在 JS 的世界裡,JS 的本質為 Sync,他的意思表示一次只能做一件事。
JS 使用的資料結構為 stack 堆疊(後進後出),需要等上層的事件做完才能做下層的事件。
https://ithelp.ithome.com.tw/upload/images/20210918/20139241K3NXCwHZrr.png
如果用函式讓他一直循環,到最後記憶體會滿出來,出現 Ranger Error,
稱做 stack overflow,跟工程師圈裡知名的查找問題的網站同名。
跟無窮迴圈不太一樣,無窮迴圈只會卡住,不會噴錯誤訊息。

以下的範例是 JS 遇到無窮迴圈的狀況:
1.因為同步的關係,JS 由上而下一次只能做一件事,console.log('JS')會加到 stack 裡,並馬上拿出執行,印出 JS。
2.而執行到迴圈時也會加到 stack 裡,因為此範例是無窮迴圈,所以會一直執行,造成卡住的狀態。
3.卡住後無法添加 console.log('Ruby') 到 stack 裡,沒辦法印出後面的 Ruby。

範例

console.log('JS');

for(let a = 1; a > 0; a++) {
  console.log("hi")
}

console.log('Ruby');

結果

JS
hi(一直執行)

非同步執行 Async

不會通通都卡在 Stack 區塊,把 JS 自己該做的事做完再做瀏覽器的事。
非 JS 內建語法,如 Web API (註解[3]) 的 setTimeout callback 不會卡在 stack 區塊裡。
一開始會先在 stack 區塊出現,接著瞬間丟給 Web API Runtime(執行環境) 執行,
等設定的時間過了之後來到 Queue 排隊區(會按照順序排列),
最後等 stack 區塊裡的程式碼跑完,setTimeout callback 才會跑到 stack 區塊執行結果。
詳細流程解說可參考註解[4]。

以下的範例是 JS 遇到 Web API 的 setTimeout 的狀況:
1.JS 會先印出來。
2.因為非同步的關係,setTimeout 函式會被丟到 Web API Runtime 執行。
3.Ruby 會被印出來。
4.過一秒後 Python 被印出。

範例

console.log('JS');

setTimeout(() => {
  console.log("Python")}
  , 1000);

console.log('Ruby');

結果

JS
Ruby
Python

或許你會想問如果我把 setTimeout 後面的時間改成 0 秒會不會改變結果。
答案是...不會
因為他是 Web API 的函式,一開始丟到 stack 後還是會被丟到 Web API Runtime 執行,
接著來到 Queue 排隊區,最後回到 JS 被執行,
這是執行順序的問題,不是時間的問題。

結論

  • JS 的同步處理:因為 JS 的資料結構是堆疊,所以一次只能處理一件事。
  • JS 的非同步處理:因為有 Web API 的幫忙,讓有些屬於 Web API 的函式可以先丟到 Web API 去執行,丟過去之後 JS 還是可以執行他的原生函式,等執行完後再處理剛剛丟到 Web API 的函式。

參考:
[1]MDN:非同步的 JavaScript 介紹
[2]Data Structure with JavaScript: Stacks
[3]MDN:Web APIs
[4]Loupe


上一篇
Day 04 HTML/JavaScript Attribute vs Property
下一篇
Day 06 JavaScript/Rails AJAX
系列文
網頁前後端寶石庫-礦坑補完計畫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言