摘要:了解事件循環機制有助于理解的執行過程,同時這也是面試常見題。那么這個回調函數將在何時由誰執行呢已知是瀏覽器環境提供的,因此瀏覽器將對它進行處理,瀏覽器會在本次事件完成,即計時結束后,將回調函數加入循環隊列中,然后等待被加入執行棧執行。
如果有人問JavaScript是什么,也許你會說它是一個單線程、非阻塞、異步、解釋型的腳本語言。那么作為一個單線程語言,它是怎么實現非阻塞、異步的?這就涉及到了瀏覽器的事件循環機制,事件循環并非由ECMAScript定義,而是在HTML Standard中定義。了解事件循環機制有助于理解JS的執行過程,同時這也是面試常見題。
在瀏覽器中,瀏覽器會提供JavaScript的運行環境,如Chrome的V8,以及一些Web API,如DOM、Ajax、setTimeout等。
如圖,在運行環境中存在一個執行棧stack,為當前正在執行的JS代碼,當調用一個普通函數時,會生成新的作用域,并入棧,待執行結束后出棧,此時不涉及異步操作。但是當調用了異步函數時,情況就有所不同了,以setTimeout為例,當調用了setTimeout后,回調函數將在一段時間后才執行,由于JavaScript是異步,它不會等待回調函數執行,而是會立即獲得結果并從上至下繼續執行代碼。那么這個回調函數將在何時由誰執行呢?已知setTimeout是瀏覽器環境提供的API,因此瀏覽器將對它進行處理,瀏覽器會在本次事件完成,即計時結束后,將回調函數加入循環隊列task queue中,然后等待被加入執行棧執行。
循環隊列中的任務被調用的時機,是當執行棧為空,即當前事件執行結束后,此時瀏覽器會查看循環隊列是否為空,在非空時以FIFO的方式調用隊列中的事件,加入執行棧,當執行棧再次為空時,再從循環隊列中查找任務,這就形成了事件循環event loop,瀏覽器通過該機制讓單線程的JS可以執行異步任務。這就可以解釋一些很常見的關于setTimeout執行順序的面試題。除了setTImeout外,常見的task任務源還有setInterval、setImmediate、I/O、UI rendering、XMLHttpRequest等。
除了以上普通的task,瀏覽器還引入了microtask的概念,microtask存儲在microtask queue中,它的執行時機與task不同,當執行棧為空時,優先調用microtask中的任務執行,因此只有當microtask queue為空時,才會調用循環隊列中的任務。常見的microtask源有promise、process.nextTick,關于promise的執行時機,也是面試較為常見的問題。
接下來就以一段代碼的執行過程為例,解釋event loop。
1 console.log(1); 2 setTimeout(() => {console.log(5)}, 0); 3 let promise = new Promise((resolve, reject) => { console.log(2) resolve() }) 4 promise.then(() => {console.log(4)}); 5 console.log(3)
請問以上代碼的執行結果?
我們試著縷一縷這些代碼的執行順序,首先這一整段代碼會被加入執行棧中,然后從上至下依次解釋執行
1:直接輸出1
2:此時調用了setTimeout,因此回調函數會在0ms后加入到循環隊列中
3:此時實例化了一個promise,會立即執行實例化時的代碼,因此會輸出2
4:此時調用了promise的then方法,該方法的回調函數會被加入到microtask queue中
5:直接輸出3
到此,執行棧執行結束,此時根據事件循環機制,首先查看microtask queue是否為空,會發現隊列中有promise.then方法加入的回調函數,將其調入執行棧執行,輸出4。執行棧再次執行結束,再查看microtask queue,此時為空,接著查看任務隊列task queue,會發現由setTimeout方法加入的回調函數,調入執行棧執行,輸出5。因此最后的輸出順序是 1 -> 2 -> 3 -> 4 -> 5
以上是關于瀏覽器端事件循環的個人理解,為什么要強調是瀏覽器端,因為從以上解釋可以看出JS只是運行在瀏覽器提供的執行環境中,事件循環其實是由瀏覽器環境實現的,除了瀏覽器,還有Node環境,而Node環境與瀏覽器環境又有著許多差別,Node環境中的事件循環與瀏覽器端存在一些差異,待有空了再寫一篇關于Node環境中的事件循環。關于瀏覽器事件循環,可以觀看https://www.youtube.com/watch...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105138.html
摘要:如果當前沒有事件也沒有定時器事件,則返回。相關資料關于的架構及設計思路的事件討論了使用線程池異步運行代碼。下一篇初窺事件機制的實現二中定時器的實現 在瀏覽器中,事件作為一個極為重要的機制,給予JavaScript響應用戶操作與DOM變化的能力;在Node.js中,事件驅動模型則是其高并發能力的基礎。 學習JavaScript也需要了解它的運行平臺,為了更好的理解JavaScript的事...
摘要:心塞塞根據規范,事件循環是通過任務隊列的機制來進行協調的。等便是任務源,而進入任務隊列的是他們指定的具體執行任務回調函數。然后當前本輪的結束,主線程可以繼續取下一個執行。 依然是:經濟基礎決定上層建筑。 說明 首先,旨在搞清常用的同步異步執行機制 其次,暫時不討論node.js的Event Loop執行機制,以下關于瀏覽器的Event Loop執行機制 最后,借鑒了很多前輩的研究文...
摘要:主線程要明確的一點是,主線程跟執行棧是不同概念,主線程規定現在執行執行棧中的哪個事件。主線程循環即主線程會不停的從執行棧中讀取事件,會執行完所有棧中的同步代碼。以上參考資料詳解中的事件循環機制中的事件循環運行機制詳解再談 showImg(https://segmentfault.com/img/remote/1460000015317437?w=1920&h=1080); 前言 大家都...
摘要:曾經的理解首先,是單線程語言,也就意味著同一個時間只能做一件事,那么為什么不是多線程呢這樣還能提高效率啊假定同時有兩個線程,一個線程在某個節點上編輯了內容,而另一個線程刪除了這個節點,這時瀏覽器就很懵逼了,到底以執行哪個操作呢所以,設計者把 Event Loop曾經的理解 首先,JS是單線程語言,也就意味著同一個時間只能做一件事,那么 為什么JavaScript不是多線程呢?這樣還能提...
摘要:前沿是基于引擎的運行環境具有事件驅動非阻塞等特點結合具有網絡編程文件系統等服務端的功能用庫進行異步事件處理線程的單線程含義實際上說的是執行同步代碼的主線程一個程序的啟動不止是分配了一個線程,而是我們只能在一個線程執行代碼當出現資源調用連接等 前沿 Node.js 是基于V8引擎的javascript運行環境. Node.js具有事件驅動, 非阻塞I/O等特點. 結合Node API, ...
摘要:深入理解引擎的執行機制靈魂三問為什么是單線程的為什么需要異步單線程又是如何實現異步的呢中的中的說說首先請牢記點是單線程語言的是的執行機制。 深入理解JS引擎的執行機制 1.靈魂三問 : JS為什么是單線程的? 為什么需要異步? 單線程又是如何實現異步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.說說setTimeout 首先,請牢記2...
閱讀 3667·2021-10-11 11:09
閱讀 1337·2021-09-24 10:35
閱讀 3422·2021-07-29 13:48
閱讀 460·2019-08-30 13:15
閱讀 2511·2019-08-30 12:53
閱讀 3183·2019-08-30 12:44
閱讀 2711·2019-08-29 16:57
閱讀 957·2019-08-29 12:26