Event Loop 其實也就這點事

前段時間在網上陸續看了不少關於 Event loop 的文章,看完也就混個眼熟,可能心裏深處對這種偏原理的知識有一些抵觸心情,看完後也都沒有去深刻理解。最近在看 Vue 的源碼,在讀到關於 nextTick 的實現時,總有一種似曾相識的感受,因而去網上查了下資料,原來 nextTick 的實現正是基於 Event loop 機制(引發重視了)。
Anyway,在翻閱了一些資料之後,將我對 Event loop 的理解記錄下來,愛看不看。javascript

Call Stack

衆所周知,JavaScript 是 one-threaded,也就意味着在執行 JavaScript 的過程當中,是 One thing at a time,而這樣的特性,正是由一個叫 Call Stack 的東西決定的(有且僅有一個)。
既然是棧,就知足 FILO 的原則。故 Call Stack 在函數運行時的表現爲:前端

  • 當有函數執行時,該函數被 push 到 Call Stack
  • 當函數執行結束時,該函數從 Call Stack 內被 pop 出
  • 若是函數內有調用到其餘函數(執行結束前),則將其餘函數再 push 到 Call Stack 中,等到調用結束時 pop 出

因而可知,若是一個函數定義以下:java

const dead = () => {
    return dead();
}

那麼當其被執行時,就會向 Call Stack 中不斷的 push 同一個函數(dead),致使整個頁面掛掉。ajax

When Call Stack Meets Sync Request

衆所又周知了,在 jQuery 提供的 Ajax 函數中,可供開發者選擇請求是 sync 仍是 async,咱們先討論 Call Stack 遇到 sync 請求時會發生什麼。vim

const name = $.ajaxSync(URL_1);
const info = $.ajaxSync(URL_2);
const work = $.ajaxSync(URL_3);

console.log(name);
console.log(info);
console.log(work);

屋漏偏逢連陰雨,此時的網絡狀態又極差,每個網絡請求從發出到成功要經歷五秒,想象一下上面這段代碼若是跑起來了,會發生什麼?
這是一件讓人絕望的事情:
隨着程序的推動,ajaxSync 函數會前後三次被 push 並 pop 出 Call Stack,而每一次從 push 到 pop 的過程須要耗費五秒鐘的時間。
不管從工程效率仍是用戶體驗的角度來講,這都是不被容許的一件事情。api

Async & Callback

爲了杜絕上面的問題,瀏覽器提供給了開發者一個叫作異步 + Callback 的解決方案。先看一段代碼:瀏覽器

console.log('kyrieliu');

setTimeout(function(){
    console.log('about Event Loop');
}, 5000);

console.log(' is writing an article ');

運行結果顯而易見。
ok,那麼這段代碼在 Call Stack 中的表現又是怎樣的呢?
基於上面文章所述,我推測:
首先,第一行代碼入棧,執行完畢後出棧;緊接着,setTimeout 入棧,而後emmm,事情有點不對勁了:若是 setTimeout 入棧執行後馬上出棧,那麼它內部的 console 爲何五秒後纔打印出來?網絡

Task Queue

問題的關鍵,是一個叫作 Task Queue 的東西。
緊接着剛纔的步驟:setTimeout入棧後執行並觸發了一個五秒的 timer,這個 timer 由 Web api 維護,至此,setTimeout執行完畢並出棧,第三個 console 入棧執行並出棧。五秒後,timer 結束計時,將回調函數 callback 下放到 task queue 中。
但 callback 還未執行,它何時執行呢?Call Stack 爲空的時候。
此時的 call stack 已經爲空,因此 callback 被 push 進棧執行並 pop 出,這樣一來就解釋得通了。
至此,正式引出 Event Loop 的概念。異步

Event Loop

If the call stack is clear and there's something in the task queue, push the first thing on the queue onto the stack.async

setTimeout(callback, 0)

在最開始接觸 JavaScript 的時候,看到上面這行代碼的我是懵蔽的,0ms 後執行 callback, WTF?
在瞭解了 Event Loop 的運行機制後,再回過頭來嘗試解釋一下這行代碼,即:在 setTimeout 入棧執行時,內部的 callback 會當即被下放到 task queue 中,但它沒法執行,由於此時的 call stack 不爲空,等到 call stack 爲空時,callback 才得以執行。

Thanks

廣而告之

我的公衆號,不止於前端
公衆號:劉凱里
相關文章
相關標籤/搜索