前段時間在網上陸續看了不少關於 Event loop 的文章,看完也就混個眼熟,可能心裏深處對這種偏原理的知識有一些抵觸心情,看完後也都沒有去深刻理解。最近在看 Vue 的源碼,在讀到關於 nextTick 的實現時,總有一種似曾相識的感受,因而去網上查了下資料,原來 nextTick 的實現正是基於 Event loop 機制(引發重視了)。
Anyway,在翻閱了一些資料之後,將我對 Event loop 的理解記錄下來,愛看不看。javascript
衆所周知,JavaScript 是 one-threaded,也就意味着在執行 JavaScript 的過程當中,是 One thing at a time,而這樣的特性,正是由一個叫 Call Stack 的東西決定的(有且僅有一個)。
既然是棧,就知足 FILO 的原則。故 Call Stack 在函數運行時的表現爲:前端
因而可知,若是一個函數定義以下:java
const dead = () => { return dead(); }
那麼當其被執行時,就會向 Call Stack 中不斷的 push 同一個函數(dead),致使整個頁面掛掉。ajax
衆所又周知了,在 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
爲了杜絕上面的問題,瀏覽器提供給了開發者一個叫作異步 + 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 的東西。
緊接着剛纔的步驟:setTimeout入棧後執行並觸發了一個五秒的 timer,這個 timer 由 Web api 維護,至此,setTimeout執行完畢並出棧,第三個 console 入棧執行並出棧。五秒後,timer 結束計時,將回調函數 callback 下放到 task queue 中。
但 callback 還未執行,它何時執行呢?Call Stack 爲空的時候。
此時的 call stack 已經爲空,因此 callback 被 push 進棧執行並 pop 出,這樣一來就解釋得通了。
至此,正式引出 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
在最開始接觸 JavaScript 的時候,看到上面這行代碼的我是懵蔽的,0ms 後執行 callback, WTF?
在瞭解了 Event Loop 的運行機制後,再回過頭來嘗試解釋一下這行代碼,即:在 setTimeout 入棧執行時,內部的 callback 會當即被下放到 task queue 中,但它沒法執行,由於此時的 call stack 不爲空,等到 call stack 爲空時,callback 才得以執行。
我的公衆號,不止於前端
![]()