日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

技术干货 | JavaScript 之事件循环(Event Loop)

發布時間:2025/3/8 javascript 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 技术干货 | JavaScript 之事件循环(Event Loop) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

導讀:學過 JavaScript(下文簡稱 JS) 的都知道它是一門單線程的、非阻塞的腳本語言。單線程意味著,JS 代碼在執行的任何時候,都只有一個主線程來處理所有的任務,這也就意味著 JS 無法進行多線程編程,但是 JS 當中卻有著無處不在的異步概念,我們如何理解呢?理解異步和非阻塞靠的就是 Event Loop(事件循環),本文就圍繞 JS 線程、同步異步、任務隊列等方面講解事件循環(Event Loop)。

文|倪萌

網易云信前端開發工程師

JS 線程

為了我們更方便容易了解事件循環,在此之前我們先簡單了解下什么叫做 JS 線程。如瀏覽器的渲染進程是多線程的,主要有以下幾個線程:

  • JS 引擎線程(主線程):負責解析 JS 腳本,運行代碼。

  • GUI 渲染線程:負責渲染瀏覽器界面,解析 HTML、CSS、構 DOM 樹和 RenderObject 樹,布局和繪制等,當界面需要重繪(Repaint)或由于某種操作引發回流 (reflow) 時,該線程就會執行。

  • 定時器觸發線程 (setTimeout):瀏覽器定時計數器并不是由 JS 引擎計數的,因為 JS 引擎是單線程的, 如果處于阻塞線程狀態就會影響記計時的準確,因此通過單獨線程來計時并觸發定時,在計時完畢后,添加到事件隊列中,等待 JS 引擎空閑后執行。

  • http 請求線程(ajax):XMLHttpRequest 連接后,通過瀏覽器新開一個線程請求,當檢測到狀態變更時,如果同時設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入事件隊列中,再由 JS 引擎執行。

  • 瀏覽器事件觸發線程 (onclick):歸屬于瀏覽器而不是 JS 引擎,用來控制事件循環,可以這么理解:JS 引擎自己都忙不過來,需要瀏覽器另開線程協助。

  • 主線程和渲染線程互斥 :JS 引擎線程與 GUI 渲染線程是互斥的,當 JS 引擎執行時 GUI 線程會被掛起(相當于被凍結了),GUI 更新會被保存在一個隊列中等到 JS 引擎空閑時立即被執行。

瀏覽器內核

  • EventLoop 輪詢處理線程:我們可以把它理解為一個中介,在主線程、異步線程與消息隊列三者之間進行交流與溝通。如下圖所示:從主線程那里順時針的看,整個的流程是循環往復的。只有當主線程的同步代碼都執行完了,才會去隊列里看看還有什么要執行的。

主線程把 setTimeout、ajax、dom.onclick 分別給三個線程,他們之間有些不同。

1、對于 setTimeout 代碼,定時器觸發線程在接收到代碼時就開始計時,時間到了將回調函數扔進消息隊列。

2、對于 ajax 代碼,http 異步線程立即發起 http 請求,請求成功后將回調函數扔進消息隊列。

3、對于 dom.onclick,瀏覽器事件線程會先監聽 dom,直到?dom 被點擊了,才將回調函數扔進消息隊列。

同步與異步

JS 分為同步任務和異步任務:

  • 同步任務:立即執行的任務隊列,比如一個簡單的函數;

  • 異步任務:請求接口發送 ajax,發送 promise,或時間計時器等等;

任務隊列(Event Queue)

什么是任務隊列呢?可以理解為一個靜態的隊列存儲結構,遵循先進先出原則:同步任務會立刻執行,進入到主線程當中;異步任務會被放到任務隊列(Event Queue)當中。

宏任務隊列和微任務隊列

宏任務(MacroTask):整體代碼 Script、UI 渲染、setTimeout、setInterval、setImmediate(Node.js 環境)。

微任務(MicroTask):Promise.then()、catch、finally。

不同點:event loop 里 MacroTask 隊列可能有多個,MicroTask 隊列只有一個。

MicroTask 優先于 MacroTask 執行,所以如果有需要優先執行的邏輯,放入 MicroTask 隊列會比 MacroTask 更早的被執行。

下面幾個代碼例子可以讓我們充分的了解各個任務之間的執行順序:

執行棧

MacroTask 和 MicroTask 都是推入棧中執行的。JS 是單線程,也就是說只有一個主線程,主線程有一個棧,每一個函數執行的時候,都會生成新的執行上下文,執行上下文會包含一些當前函數的參數、局部變量之類的信息,它會被推入棧中,正在執行的上下文始終處于棧的頂部。當函數執行完后,它的執行上下文會從棧彈出。

總結

同步和異步任務分別進入不同的執行環境, 先執行同步任務,把異步任務放入循環隊列當中,等待同步任務執行完,再執行隊列中的異步任務。異步任務先執行微觀任務,再執行宏觀任務。一直這樣循環,反復執行,就是我們說的 Event Loop (事件循環)。

事件循環是 JS 這門語言中非常重要且基礎的概念。讓我們可以清楚的了解事件循環的執行順序和每一個階段的特點,可以使我們對一段異步代碼的執行順序有一個清晰的認識,從而減少代碼運行的不確定性。合理的使用各種延遲事件的方法,有助于代碼更好的按照其優先級去執行。

如果在閱讀期間您發現了文章中的一些問題,歡迎在留言中提出,感謝您閱讀此文章。

?作者介紹?

倪萌,網易云信 web 前端開發工程師,目前在從事云信金融線業務相關開發工作。

?相關閱讀推薦?

  • 技術系列課回顧 | 網易云信變聲技術之變調不變速算法

  • 技術干貨 | C++20 四大特性之一:Module 特性詳解

  • 技術實踐 | 網易云信視頻轉碼提速之分片轉碼

總結

以上是生活随笔為你收集整理的技术干货 | JavaScript 之事件循环(Event Loop)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。