首頁 web前端 js教程 詳解JavaScript事件循環機制

詳解JavaScript事件循環機制

Oct 08, 2018 pm 03:30 PM
javascript

這篇文章跟大家分享了關於JavaScript事件循環機制的相關知識點內容,有興趣的朋友們可以學習參考下。

眾所周知,JavaScript 是一門單執行緒語言,雖然在 html5 中提出了 Web-Worker ,但這並未改變 JavaScript 是單執行緒這一核心。可看HTML規格中的這段話:

To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described in this section. There are two kinds of event loops: those for browsing contexts, and those for workers.

為了協調事件、使用者互動、腳本、UI 渲染和網路處理等行為,使用者引擎必須使用event loops。 Event Loop 包含兩類:一類是基於 Browsing Context ,另一種是基於 Worker ,二者是獨立運作的。以下本文用一個例子,著重講解下基於 Browsing Context 的事件循環機制。

來看下面這段JavaScript 程式碼:

console.log('script start');

setTimeout(function() {
 console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
 console.log('promise1');
}).then(function() {
 console.log('promise2');
});

console.log('script end');
登入後複製
登入後複製

先猜測這段程式碼的輸出順序是什麼,再去瀏覽器控制台輸入一下,看看實際輸出的順序和你猜測出的順序是否一致,如果一致,那就說明,你對JavaScript 的事件循環機制還是有一定了解的,繼續往下看可以鞏固下你的知識;而如果實際輸出的順序和你的猜測不一致,那麼本文下面的部分會為你答疑解惑。

任務佇列

所有的任務可以分為同步任務和非同步任務,同步任務,顧名思義,就是立即執行的任務,同步任務一般會直接進入到主執行緒中執行;而非同步任務,就是非同步執行的任務,例如ajax網路請求,setTimeout 定時函數等都屬於非同步任務,非同步任務會透過任務佇列( Event Queue )的機制來進行協調。具體的可以用下面的圖來大致說明一下:

同步和非同步任務分別進入不同的執行環境,同步的進入主線程,即主執行棧,異步的進入Event Queue 。主執行緒內的任務執行完畢為空,會去 Event Queue 讀取對應的任務,推入主執行緒執行。上述過程的不斷重複就是我們說的 Event Loop (事件循環)。

在事件循環中,每進行一次循環操作稱為tick,透過閱讀規範可知,每一次tick 的任務處理模型是比較複雜的,其關鍵的步驟可以總結如下:

  • 在此次tick 中選擇最先進入佇列的任務( oldest task ),如果有則執行(一次)

  • 檢查是否存在Microtasks ,如果存在則不停地執行,直到清空Microtask Queue

  • #更新render

主執行緒重複執行上述步驟

可以用一張圖來說明下流程:

這裡相信有人會想問,什麼是microtasks ?規範中規定,task分為兩大類, 分別是Macro Task (宏任務)和Micro Task(微任務), 並且每個宏任務結束後, 都要清空所有的微任務,這裡的Macro Task也是我們常說的task ,有些文章並沒有對其做區分,後面文章所提及的task皆看做宏任務( macro task)。

(macro)task 主要包含:script( 整體程式碼)、setTimeout、setInterval、I/O、UI 互動事件、setImmediate(Node.js 環境)

microtask主要包含:Promise、 MutaionObserver、process.nextTick(Node.js 環境)

setTimeout/Promise 等API便是任務來源,而進入任務佇列的則是由他們指定的特定執行任務。來自不同任務來源的任務會進入到不同的任務佇列。其中 setTimeout 與 setInterval 是同源的。

分析範例程式碼

千言萬語,不如就著例子講來的清楚。下面我們可以依照規範,一步一步執行解析下上面的例子,先貼一下例子程式碼(免得你往上翻)。

console.log('script start');

setTimeout(function() {
 console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
 console.log('promise1');
}).then(function() {
 console.log('promise2');
});

console.log('script end');
登入後複製
登入後複製

整體script 作為第一個巨集任務進入主線程,遇到console.log,輸出script start

  • 遇到setTimeout,其回呼函數被分發到巨集任務Event Queue 中

  • 遇到Promise,其then函數被分到到微任務Event Queue 中,記為then1,之後又遇到了then 函數,將其分到微任務Event Queue 中,記為then2

  • 遇到console.log,輸出script end

至此,Event Queue 中存在三個任務,如下表:

宏任務微任務
########### setTimeout######then1############-#######then2############
  • 执行微任务,首先执行then1,输出 promise1, 然后执行 then2,输出 promise2,这样就清空了所有微任务

  • 执行 setTimeout 任务,输出 setTimeout 至此,输出的顺序是:script start, script end, promise1, promise2, setTimeout

so,你猜对了吗?

看看你掌握了没

再来一个题目,来做个练习:

console.log('script start');

setTimeout(function() {
 console.log('timeout1');
}, 10);

new Promise(resolve => {
 console.log('promise1');
 resolve();
 setTimeout(() => console.log('timeout2'), 10);
}).then(function() {
 console.log('then1')
})

console.log('script end');
登入後複製

这个题目就稍微有点复杂了,我们再分析下:

首先,事件循环从宏任务 (macrotask) 队列开始,最初始,宏任务队列中,只有一个 scrip t(整体代码)任务;当遇到任务源 (task source) 时,则会先分发任务到对应的任务队列中去。所以,就和上面例子类似,首先遇到了console.log,输出 script start; 接着往下走,遇到 setTimeout 任务源,将其分发到任务队列中去,记为 timeout1; 接着遇到 promise,new promise 中的代码立即执行,输出 promise1, 然后执行 resolve ,遇到 setTimeout ,将其分发到任务队列中去,记为 timemout2, 将其 then 分发到微任务队列中去,记为 then1; 接着遇到 console.log 代码,直接输出 script end 接着检查微任务队列,发现有个 then1 微任务,执行,输出then1 再检查微任务队列,发现已经清空,则开始检查宏任务队列,执行 timeout1,输出 timeout1; 接着执行 timeout2,输出 timeout2 至此,所有的都队列都已清空,执行完毕。其输出的顺序依次是:script start, promise1, script end, then1, timeout1, timeout2

用流程图看更清晰:

总结

有个小 tip:从规范来看,microtask 优先于 task 执行,所以如果有需要优先执行的逻辑,放入microtask 队列会比 task 更早的被执行。

最后的最后,记住,JavaScript 是一门单线程语言,异步操作都是放到事件循环队列里面,等待主执行栈来执行的,并没有专门的异步执行线程。

以上就是本章的全部内容,更多相关教程请访问JavaScript视频教程

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

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

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

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

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

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Java教學
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1270
29
C# 教程
1249
24
如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

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

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

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

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

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

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

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

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

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

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

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

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

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

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

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

See all articles