iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 6
0

今天來看看JS,非同步背後的原理,在課程影片中提到:

JavaScript是一個單執行緒同步的程式,它逐行執行程式碼,並不會非同步的執行程式。

等等,同步?
JS的特色之一不就是非同步嗎?
繼續看下去:
 
撇開node.js先不說,JS在瀏覽器執行時依賴引擎來驅動,而瀏覽器不是只有JavaScript引擎的存在,還有其他引擎在處理瀏覽器的其他狀態、程式。有可以呈現東西到瀏覽器畫面上的渲染引擎(Rendering Engine),也有其他專門處理http請求的東西存在。
 
JS引擎可以和瀏覽器的其他引擎、處理器互動,這個互動行為是非同步的,但JS引擎自己在運作JavaScript是同步的。如果有非同步的操作,那會發生什麼事呢?

JS引擎內的等待列稱為事件佇列Event Queue,如果有事件發生,如滑鼠點擊事件,JS引擎會先將事件放在事件佇列Event Queue,當執行環境的程式都執行完成後,JS才會開始注意事件佇列,此時檢查是否有函式被事件觸發,當有事件發生如點擊事件,它會創造執行環境給這個對應的函式執行。

JS在瀏覽器的非同步行為,其實是指將非同步事件放到事件佇列,而自己執行同步程式結束後,才處理事件。如果事件觸發函式,就創造執行環境給對應函式,所以說,當瀏覽器的其他引擎或處理器有事件、狀態發生並與JS引擎互動時,這些事件就會被註冊進事件佇列裡。

看看影片中的程式碼範例

function waitThreeSeconds() {
    var ms = 3000 + new Date().getTime();
    while (new Date() < ms){}
    console.log('finished function');
}

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

document.addEventListener('click', clickHandler);

waitThreeSeconds();
console.log('finished execution');

說明:
function waitThreeSeconds()
呼叫它會在3秒後印出finished function

function clickHandler()
對應下面的document.addEventListener('click', clickHandler);
當瀏覽器監聽到點擊事件,執行clickHandler(),印出click event!

waitThreeSeconds();
呼叫函式waitThreeSeconds

console.log('finished execution');
印出finished execution

當在影片聽到function waitThreeSeconds()3000 + new Date().getTime();3秒說明時,瞬間想了一下,為何這裡不使用常見的setTimeout來處理?
...下一秒瞬間回神,阿setTimeout也是非同步的(敲頭),作者是簡化例子中的同步、非同步判斷,好讓觀眾能易懂,如此一來上述程式中只有click點擊事件是非同步的。

拉回來,當瀏覽器載入後,顯示印出的東西順序會是如何?
點擊事件印出的內容,有辦法比waitThreeSeconds(3秒後才印出東西)或最下面的console.log('finished execution')更早印出來嗎?

執行程式,在網頁載入後快速點擊頁面,結果為:


3是我猛按的結果,不要理這個數字...

說明:
waitThreeSeconds()執行完成、全域的console.log('finished execution');也執行完成,點擊事件才執行其對應函式clickHandler(),因為JS會先把執行時期的同步程式都執行完,才處理事件。
也就是說執行時間太長的同步程式可以干擾非同步事件的處理時間,在開發時得注意這點。
 
 
 
小結
同步與非同步是JS中極為重要的一環,當初學習AJAX時,常在書上或聽人說JS會註冊非同步事件,向誰註冊呢?就是事件佇列Event Queue啦。
 
今天的筆記內容可以參照Udemy課程:JavaScript 全攻略:克服JS 的奇怪部分2-13、2-18


上一篇
Day05 變數與函式環境、外部參照
下一篇
Day07 型別與運算子
系列文
JavaScript基礎二三事30

尚未有邦友留言

立即登入留言