搜尋
首頁web前端js教程詳解javascript瀏覽器的事件循環機制

詳解javascript瀏覽器的事件循環機制

Oct 20, 2018 pm 04:15 PM
es6javascriptnode.js

這篇文章帶給大家的內容是關於詳解javascript瀏覽器的事件循環機制,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

拋在前面的問題:

單執行緒如何做到非同步

事件循環的過程是怎樣的

macrotask 和microtask 是什麼,它們有何區別

單線程和非同步

提到js,就會想到單線程,非同步,那麼單線程是如何做到非同步的呢?概念先行,先要了解下單線程和非同步之間的關係。

js的任務分為同步和非同步兩種,它們的處理方式也不同,同步任務是直接在主執行緒上排隊執行,非同步任務則會被放到任務佇列中,若有多個任務(非同步任務)則要在任務佇列中排隊等待,任務佇列類似一個緩衝區,任務下一步會被移到呼叫堆疊(call stack),然後主執行緒執行呼叫堆疊的任務。

單執行緒是指js引擎中負責解析執行js程式碼的執行緒只有一個(主執行緒),即每次只能做一件事,而我們知道一個ajax請求,主執行緒在等待它回應的同時是會去做其它事的,瀏覽器先在事件表註冊ajax的回調函數,響應回來後回調函數被添加到任務隊列中等待執行,不會造成線程阻塞,所以說js處理ajax請求的方式是異步的。

總而言之,檢查呼叫堆疊是否為空,以及確定把哪個task加入呼叫堆疊的這個過程就是事件循環,而js實作非同步的核心就是事件循環。

呼叫堆疊和任務佇列

顧名思義,呼叫堆疊是一個堆疊結構,函數呼叫會形成一個棧幀,幀中包含了當前執行函數的參數和局部變數等上下文信息,函數執行完後,它的執行上下文會從堆疊中彈出。

下圖就是呼叫堆疊和任務佇列的關係圖

詳解javascript瀏覽器的事件循環機制

#事件循環

關於事件循環, HTML規範的介紹

There must be at least one event loop per user agent, and at most one event loop per unit of related similar-origin browsing contexts.
An event loop has one or more task queues.
Each task is defined as coming from a specific task source.

從規範理解,瀏覽器至少有一個事件循環,一個事件循環至少有一個任務佇列(macrotask),每個外任務都有自己的分組,瀏覽器會為不同的任務群組設定優先權。

macrotask & microtask

規格有提到兩個概念,但沒有詳細介紹,查閱一些資料大概可總結如下:

macrotask:包含執行整體的js程式碼,事件回調,XHR回調,定時器(setTimeout/setInterval/setImmediate),IO操作,UI render

microtask:更新應用程式狀態的任務,包括promise回調,MutationObserver,process.nextTick,Object.observe

其中setImmediate和process.nextTick是nodejs的實現,在nodejs篇會詳細介紹。

事件處理過程

關於macrotask和microtask的理解,光這樣看會有些晦澀難懂,結合事件循壞的機制理解清晰很多,下面這張圖可以說是介紹得非常清楚了。

詳解javascript瀏覽器的事件循環機制

總結起來,一次事件循環的步驟包括:

1. 檢查macrotask佇列是否為空,非空則到2,為空則到3
2. 執行macrotask中的一個任務
3. 繼續檢查microtask佇列是否為空,若有則到4,否則到5
4. 取出microtask中的任務執行,執行完成返回步驟3
5.執行視圖更新

mactotask & microtask的執行順序

詳解javascript瀏覽器的事件循環機制

讀完這麼多乾巴巴的概念介紹,不如看一段程式碼感受下

console.log('start')
setTimeout(function() {
console.log('setTimeout')
}, 0)
Promise.resolve().then(function() {
console.log('promise1')
}).then(function() {
console.log('promise2')
})
console.log('end')

列印台輸出的log順序是什麼?結合上述的步驟分析,係不繫so easy~

詳解javascript瀏覽器的事件循環機制

首先,全域程式碼(main())壓入呼叫堆疊執行,列印start;

接下來setTimeout壓入macrotask佇列,promise.then回呼放入microtask佇列,最後執行console.log('end'),列印出end;

至此,呼叫堆疊中的程式碼執行完成,回顧macrotask的定義,我們知道全域程式碼屬於macrotask,macrotask執行完,那接下來就是執行microtask佇列的任務了,執行promise回呼印出promise1;

promise回调函数默认返回undefined,promise状态变为fullfill触发接下来的then回调,继续压入microtask队列,event loop会把当前的microtask队列一直执行完,此时执行第二个promise.then回调打印出promise2;

这时microtask队列已经为空,从上面的流程图可以知道,接下来主线程会去做一些UI渲染工作(不一定会做),然后开始下一轮event loop,执行setTimeout的回调,打印出setTimeout;

这个过程会不断重复,也就是所谓的事件循环。

视图渲染的时机

回顾上面的事件循环示意图,update rendering(视图渲染)发生在本轮事件循环的microtask队列被执行完之后,也就是说执行任务的耗时会影响视图渲染的时机。通常浏览器以每秒60帧(60fps)的速率刷新页面,据说这个帧率最适合人眼交互,大概16.7ms渲染一帧,所以如果要让用户觉得顺畅,单个macrotask及它相关的所有microtask最好能在16.7ms内完成。

但也不是每轮事件循环都会执行视图更新,浏览器有自己的优化策略,例如把几次的视图更新累积到一起重绘,重绘之前会通知requestAnimationFrame执行回调函数,也就是说requestAnimationFrame回调的执行时机是在一次或多次事件循环的UI render阶段。

以下代码可以验证

setTimeout(function() {console.log('timer1')}, 0)
requestAnimationFrame(function(){
	console.log('requestAnimationFrame')
	})
	setTimeout(function() {console.log('timer2')}, 0)
	new Promise(function executor(resolve) {
	console.log('promise 1')
	resolve()
	console.log('promise 2')
	}).then(function() {
	console.log('promise then')
	})
	console.log('end')

詳解javascript瀏覽器的事件循環機制

詳解javascript瀏覽器的事件循環機制

可以看到,结果1中requestAnimationFrame()是在一次事件循环后执行,而在结果2,它的执行则是在三次事件循环结束后。

总结

1、事件循环是js实现异步的核心

2、每轮事件循环分为3个步骤:

a) 执行macrotask队列的一个任务
b) 执行完当前microtask队列的所有任务
c) UI render

3、浏览器只保证requestAnimationFrame的回调在重绘之前执行,没有确定的时间,何时重绘由浏览器决定

以上是詳解javascript瀏覽器的事件循環機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:github。如有侵權,請聯絡admin@php.cn刪除
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器