[JS奇怪的世界]No.12 關於非同步回呼

關於非同步回呼

前面某一章節我有講過 JavaScipt 的同步執行,想必你也聽過很多所謂的非同步,但非同步是什麼?

非同步

非同步

非同步的意思是說在一個時間點內一個正在執行中的程式又開始執行另一個程式的意思,聽起來很像繞口令吧?我們前面有講過 JavaScript 它是一次執行一行程式碼,那 JavaScript 又該如何處理非同步事件呢?

首先我們已經了解了執行堆還有執行環境,那當函數執行完畢後就會離開執行堆(釋放),而 JavaScript 等待的過程中在 JavaScript 引擎稱為事件佇列 (event queue),而這裡面的事件、事件通知,都是即將可能要發生的。

所以當執行堆全部都執行完畢後 JavaScript 就會開始注意事件佇列(event queue),舉例 click 事件,JavaScript 會注意到它是否會觸發某些函數,如果會就會把函數丟入執行堆中,當事件一發生就會開始創造執行環境給這個函數,然後這個事件就結束並釋放,接下來就會輪到下一個事件佇列(舉例 HTTP Request)以此類推…

但是要注意事件佇列只會在執行堆為空的時候才會執行事件佇列(event queue),那這真的是非同步嗎?不,還是同步執行,JavaScript 還是一樣一行一行的執行程式碼。

讓我們這邊來看課程的程式範例 ↓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function waitThreeSceonds() {
var ms = 3000 + new Date().getTime();
while(new Date() < ms){}
console.log('finished function');
}

function clickHandler() {
console.log('click event!');
}

document.addEventListener('click', clickHandler);

waitThreeSceonds()

console.log('finished execution');

依照這範例我們可以發現 console.log('finished execution'); 會立刻出現,然後過一段時間才會出現 console.log('finished function');,接下來當我們點擊畫面時就會出現 console.log('click event!');,注意到了嗎? JavaScript 會先執行完畢應該要執行的函數再來執行下一行程式碼,所以會像這樣子。

事件佇列

所以我們可以一執行這個函數後立刻點擊畫面你會發現 console.log('click event!'); 並沒有出現,它會等到 waitThreeSceonds() 執行完畢才出現。

事件佇列

由此可知 JavaScript 會等候執行堆清空後再去執行下一個事件,而過程中它會將事件儲存在事件佇列(event queue),所以執行時間的長短將會看事件佇列來決定,這也是就是 JavaScript 如何處理同步與非同步的方式。

圖源

JavaScript 全攻略:克服 JS 奇怪的部分

0%