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