摘要:同時,如果執(zhí)行的過程中發(fā)現(xiàn)其他函數(shù),繼續(xù)入棧然后執(zhí)行。上面我們討論的其實都是同步代碼,代碼在運行的時候只用調用棧解釋就可以了。
序
Event Loop 這個概念相信大家或多或少都了解過,但是有一次被一個小伙伴問到它具體的原理的時候,感覺自己只知道個大概印象,于是計劃著寫一篇文章,用輸出倒逼輸入,讓自己重新學習這個概念,同時也能幫助更多的人理解它~
概念JavaScript 是一門 單線程 語言,即同一時間只能執(zhí)行一個任務,即代碼執(zhí)行是同步并且阻塞的。
eg. 這就像只有一個窗口的銀行,客戶需要一個一個排隊辦理業(yè)務。
只能同步執(zhí)行肯定是有問題的,所以 JS 有了一個用來實現(xiàn)異步的函數(shù):setTimeout
下面要講的 Event Loop 就是為了確保 異步代碼 可以在 同步代碼 執(zhí)行后繼續(xù)執(zhí)行的。
由于涉及到的相關概念較多,我們先從最簡單的來。
隊列(Queue)隊列 是一種 FIFO(First In, First Out) 的數(shù)據(jù)結構,它的特點就是 先進先出
eg. 生活中最常見的例子就是排隊啦,排在隊伍最前面的人最先被提供服務。棧(Stack)
棧 是一種 LIFO(Last In, First Out)的數(shù)據(jù)結構,特點即 后進先出。
eg. 大家都吃過桶裝薯片吧~薯片在包裝的時候只能從頂部放入,而吃的時候也只能從頂部拿出,這就叫后進先出哈調用棧(Call Stack)
棧我們已經(jīng)知道了,那么什么是 調用棧 呢 ?
它本質上當然還是個棧啦 廢話,關鍵在于它里面裝的東西,是一個個待執(zhí)行的函數(shù)。
Event Loop 會一直檢查 Call Stack 中是否有函數(shù)需要執(zhí)行,如果有,就從棧頂依次執(zhí)行。同時,如果執(zhí)行的過程中發(fā)現(xiàn)其他函數(shù),繼續(xù)入棧然后執(zhí)行。
先拿兩個函數(shù)來說:
棧空
現(xiàn)在執(zhí)行到一個 函數(shù)A,函數(shù)A 入棧
函數(shù)A 又調用了 函數(shù)B,函數(shù)B 入棧
函數(shù)B 執(zhí)行完后 出棧
然后繼續(xù)執(zhí)行 函數(shù)A,執(zhí)行完后A也 出棧
???/p>
更復雜一點的話,來看一段代碼:
這段代碼在 調用棧中的運行順序如下圖:
這個調用棧其實大家經(jīng)常會見到,就是在控制臺報錯的時候,錯誤信息顯示的就是當前時刻調用棧的狀態(tài)。
But, 上面我們討論的其實都是同步代碼,代碼在運行的時候只用 調用棧 解釋就可以了。
那么,假如我們發(fā)起了一個網(wǎng)絡請求(request),或者設置了一個定時器延時(setTimeout),一段時間后的代碼(回調函數(shù))肯定不是直接被加到調用棧吧?
這時就要引出 事件表格(Event Table) 和 事件隊列 (Event Queue) 了
Event TableEvent Table 可以理解成一張 事件->回調函數(shù) 對應表
它就是用來存儲 JavaScript 中的異步事件 (request, setTimeout, IO等) 及其對應的回調函數(shù)的列表Event Queue
Event Queue 簡單理解就是 回調函數(shù) 隊列,所以它也叫 Callback Queue
當 Event Table 中的事件被觸發(fā),事件對應的 回調函數(shù) 就會被 push 進這個 Event Queue,然后等待被執(zhí)行Event Loop
先來看一個流程圖:
開始,任務先進入 Call Stack
同步任務直接在棧中等待被執(zhí)行,異步任務從 Call Stack 移入到 Event Table 注冊
當對應的事件觸發(fā)(或延遲到指定時間),Event Table 會將事件回調函數(shù)移入 Event Queue 等待
當 Call Stack 中沒有任務,就從 Event Queue 中拿出一個任務放入 Call Stack
而 Event Loop 指的就是這一整個圈圈:
它不停檢查 Call Stack 中是否有任務(也叫棧幀)需要執(zhí)行,如果沒有,就檢查 Event Queue,從中彈出一個任務,放入 Call Stack 中,如此往復循環(huán)。
好啦,不知道有沒有看明白呢?放一張更經(jīng)典的圖:
其中與 Event Queue 對應的還有一個叫 Job Queue,它主要是用來執(zhí)行 Promise 的,這兩種 Queue 有什么區(qū)別呢?
這就涉及到 宏任務 (macro task) 和 微任務 (micro task) 了,我們放在下篇再講~
參考文章原文鏈接
MDN EventLoop
javascript-event-loop
understanding-js-the-event-loop
這一次,徹底弄懂JavaScript執(zhí)行機制
understanding-event-loop-call-stack-event-job-queue-in-javascript
歡迎關注我的公眾號:碼力全開
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/109906.html
摘要:常見應用則是為了完成一些更新應用程序狀態(tài)的較小的任務,如處理的回調和的修改,以便讓這些任務在瀏覽器重新渲染之前執(zhí)行。常見應用執(zhí)行順序的實現(xiàn)需要至少一個和至少一個。 簡介 我們在上一篇 《淺析 JS 中的EventLoop 事件循環(huán)》 中提到一個 Event Queue,其實在事件循環(huán)中 queue 一共有兩種,還有一種叫 Job Queue 其中 Event Queue 在 HTML...
摘要:前沿是基于引擎的運行環(huán)境具有事件驅動非阻塞等特點結合具有網(wǎng)絡編程文件系統(tǒng)等服務端的功能用庫進行異步事件處理線程的單線程含義實際上說的是執(zhí)行同步代碼的主線程一個程序的啟動不止是分配了一個線程,而是我們只能在一個線程執(zhí)行代碼當出現(xiàn)資源調用連接等 前沿 Node.js 是基于V8引擎的javascript運行環(huán)境. Node.js具有事件驅動, 非阻塞I/O等特點. 結合Node API, ...
摘要:事件循環(huán)當進程啟動時,會創(chuàng)建一個循環(huán),每個循環(huán)通過內部的觀察者來查看是否有事件需要處理,如果有就取出事件和它相關的回調函數(shù)去執(zhí)行,執(zhí)行完以后就進入下一個循環(huán),如果不再有就退出進程。 前言 在學習eventloop之前,我們需要復習一下js的單線程和異步。雖說js是單線程的,但是在瀏覽器和Node中都做了相應的處理。如瀏覽器中的web workers(工作線程),Node中的child_...
摘要:事件循環(huán)當進程啟動時,會創(chuàng)建一個循環(huán),每個循環(huán)通過內部的觀察者來查看是否有事件需要處理,如果有就取出事件和它相關的回調函數(shù)去執(zhí)行,執(zhí)行完以后就進入下一個循環(huán),如果不再有就退出進程。 前言 在學習eventloop之前,我們需要復習一下js的單線程和異步。雖說js是單線程的,但是在瀏覽器和Node中都做了相應的處理。如瀏覽器中的web workers(工作線程),Node中的child_...
摘要:事件循環(huán)當進程啟動時,會創(chuàng)建一個循環(huán),每個循環(huán)通過內部的觀察者來查看是否有事件需要處理,如果有就取出事件和它相關的回調函數(shù)去執(zhí)行,執(zhí)行完以后就進入下一個循環(huán),如果不再有就退出進程。 前言 在學習eventloop之前,我們需要復習一下js的單線程和異步。雖說js是單線程的,但是在瀏覽器和Node中都做了相應的處理。如瀏覽器中的web workers(工作線程),Node中的child_...
閱讀 1813·2021-10-19 13:30
閱讀 1375·2021-10-14 09:48
閱讀 1587·2021-09-22 15:17
閱讀 2035·2019-08-30 15:52
閱讀 3303·2019-08-30 11:23
閱讀 2016·2019-08-29 15:27
閱讀 920·2019-08-29 13:55
閱讀 784·2019-08-26 14:05