詳解javascript瀏覽器的事件循環機制
這篇文章帶給大家的內容是關於詳解javascript瀏覽器的事件循環機制,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
拋在前面的問題:
單執行緒如何做到非同步
事件循環的過程是怎樣的
macrotask 和microtask 是什麼,它們有何區別
單線程和非同步
提到js,就會想到單線程,非同步,那麼單線程是如何做到非同步的呢?概念先行,先要了解下單線程和非同步之間的關係。
js的任務分為同步和非同步兩種,它們的處理方式也不同,同步任務是直接在主執行緒上排隊執行,非同步任務則會被放到任務佇列中,若有多個任務(非同步任務)則要在任務佇列中排隊等待,任務佇列類似一個緩衝區,任務下一步會被移到呼叫堆疊(call stack),然後主執行緒執行呼叫堆疊的任務。
單執行緒是指js引擎中負責解析執行js程式碼的執行緒只有一個(主執行緒),即每次只能做一件事,而我們知道一個ajax請求,主執行緒在等待它回應的同時是會去做其它事的,瀏覽器先在事件表註冊ajax的回調函數,響應回來後回調函數被添加到任務隊列中等待執行,不會造成線程阻塞,所以說js處理ajax請求的方式是異步的。
總而言之,檢查呼叫堆疊是否為空,以及確定把哪個task加入呼叫堆疊的這個過程就是事件循環,而js實作非同步的核心就是事件循環。
呼叫堆疊和任務佇列
顧名思義,呼叫堆疊是一個堆疊結構,函數呼叫會形成一個棧幀,幀中包含了當前執行函數的參數和局部變數等上下文信息,函數執行完後,它的執行上下文會從堆疊中彈出。
下圖就是呼叫堆疊和任務佇列的關係圖
#事件循環
關於事件循環, 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的理解,光這樣看會有些晦澀難懂,結合事件循壞的機制理解清晰很多,下面這張圖可以說是介紹得非常清楚了。
總結起來,一次事件循環的步驟包括:
1. 檢查macrotask佇列是否為空,非空則到2,為空則到3
2. 執行macrotask中的一個任務
3. 繼續檢查microtask佇列是否為空,若有則到4,否則到5
4. 取出microtask中的任務執行,執行完成返回步驟3
5.執行視圖更新
mactotask & microtask的執行順序
讀完這麼多乾巴巴的概念介紹,不如看一段程式碼感受下
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~
首先,全域程式碼(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')
可以看到,结果1中requestAnimationFrame()是在一次事件循环后执行,而在结果2,它的执行则是在三次事件循环结束后。
总结
1、事件循环是js实现异步的核心
2、每轮事件循环分为3个步骤:
a) 执行macrotask队列的一个任务
b) 执行完当前microtask队列的所有任务
c) UI render
3、浏览器只保证requestAnimationFrame的回调在重绘之前执行,没有确定的时间,何时重绘由浏览器决定
以上是詳解javascript瀏覽器的事件循環機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數
