JavaScript事件循環

目錄

JavaScript 執行機制與事件循環

一、同步與異步代碼

1. 同步代碼(Synchronous Code)

2. 異步代碼(Asynchronous Code)

二、事件循環(Event Loop)

1. 核心組成

2.?事件循環基本流程

3. 運行機制

三、異步操作分類

1. 任務類型對比

2.?宏任務(Macrotasks)

3.?微任務(Microtasks)

4. 執行順序規則

5. 代碼執行順序示例

6. 常見問題

四、Promise的同步異步問題

五、Node.js 與瀏覽器的事件循環差異

六、關鍵總結

示例


JavaScript 是單線程語言,但其通過?事件循環(Event Loop)?和?任務隊列(Task Queue)?實現了非阻塞異步執行。


一、同步與異步代碼

1. 同步代碼(Synchronous Code)

  • 特點

    • 順序執行,阻塞后續代碼

    • 直接在主線程(調用棧)執行

    • 典型場景:普通函數調用、數學運算

    console.log('Start');
    let sum = 0;
    for (let i = 0; i < 1e6; i++) sum += i;
    console.log('End'); // 必須等待循環執行完

2. 異步代碼(Asynchronous Code)

  • 特點

    • 非阻塞執行,后續代碼無需等待

    • 通過任務隊列管理

    • 典型場景:setTimeoutfetchPromiseDOM事件

    console.log('Start');
    setTimeout(() => console.log('Timeout'), 0);
    console.log('End'); 
    // 輸出順序:Start → End → Timeout

二、事件循環(Event Loop)

1. 核心組成

組件作用
調用棧 (Call Stack)存放同步執行代碼(LIFO結構)
任務隊列 (Task Queue)存放待處理的異步任務
Web APIs瀏覽器提供的異步API(如DOM、定時器)

2.?事件循環基本流程

事件循環是 JavaScript 處理異步代碼的核心機制,其基本流程如下:

  1. 執行同步代碼
    先執行當前調用棧中的所有同步任務(如函數調用、變量賦值)。

  2. 處理微任務隊列
    同步代碼執行完畢后,立即清空微任務隊列(Microtask Queue)中的所有任務(如?Promise.then)。

  3. 渲染頁面(如有需要)
    執行 UI 渲染(布局、繪制),但瀏覽器會智能合并渲染操作以優化性能。

  4. 處理宏任務隊列
    宏任務隊列(Macrotask Queue)中取出一個任務執行,回到步驟 1 開始新的事件循環。

3. 運行機制

st=>start: 開始執行
op1=>operation: 執行同步代碼
op2=>operation: 遇到異步任務
op3=>operation: 注冊到Web APIs
op4=>operation: Web API完成,回調推入任務隊列
cond=>condition: 調用棧是否為空?
op5=>operation: 取出隊列首個任務推入調用棧
e=>end: 結束st->op1->op2->op3->op4->cond
cond(yes)->op5->cond
cond(no)->e

三、異步操作分類

1. 任務類型對比

特性宏任務(Macrotask)微任務(Microtask)
常見類型setTimeoutsetInterval、I/O操作、UI渲染Promise.thenMutationObserverprocess.nextTick(Node.js)
執行時機每輪事件循環執行一個宏任務當前宏任務執行完畢后立即執行所有微任務
優先級

2.?宏任務(Macrotasks)

  • 常見類型

    • setTimeout?/?setInterval

    • I/O 操作(文件讀寫、網絡請求)

    • UI 渲染(瀏覽器)

    • requestAnimationFrame(瀏覽器)

  • 特點:每次事件循環處理一個宏任務。

  • 微任務優先級高于宏任務:每執行完一個宏任務后,會立即清空所有微任務。

3.?微任務(Microtasks)

  • 常見類型

    • Promise.then?/?catch?/?finally

    • MutationObserver(瀏覽器)

    • queueMicrotask

  • 特點:在當前宏任務結束后、下一個宏任務開始前執行所有微任務。

  • 微任務可嵌套:若在微任務中生成新的微任務,新微任務會在當前事件循環中被執行。

4. 執行順序規則

  1. 執行當前宏任務中的同步代碼

  2. 執行該宏任務產生的所有微任務

  3. 執行下一個宏任務

  4. 循環往復(每次循環稱為一個"tick")

5. 代碼執行順序示例

console.log('Start');setTimeout(() => {console.log('Timeout');
}, 0);Promise.resolve().then(() => console.log('Promise 1')).then(() => console.log('Promise 2'));console.log('End');

輸出順序

Start
End
Promise 1
Promise 2
Timeout

執行步驟

  1. 同步代碼依次執行,輸出?Start?和?End

  2. setTimeout?回調進入宏任務隊列。

  3. Promise.then?回調進入微任務隊列。

  4. 同步代碼執行完畢,執行所有微任務(Promise 1Promise 2)。

  5. 執行下一個宏任務(Timeout)。

6. 常見問題

  1. 為什么微任務優先級高?
    微任務通常用于更緊急的更新(如 Promise 狀態變更),確保在渲染前完成數據更新,提升用戶體驗。

  2. 如何避免微任務饑餓?
    避免在微任務中無限遞歸添加微任務,否則宏任務無法執行,導致頁面卡死。

  3. requestAnimationFrame?是宏任務還是微任務?
    它屬于渲染階段的宏任務,用于在下次重繪前執行動畫更新,優先級高于普通宏任務(如?setTimeout)。


四、Promise的同步異步問題

1. 同步執行:Promise 的構造函數和其執行器函數中的代碼是同步執行的。

2. 異步回調.then().catch()?等回調函數是異步的微任務,會在當前同步代碼執行完畢后執行。

3. 示例

console.log('1. 同步代碼開始');const promise = new Promise((resolve) => {console.log('2. Promise 執行器函數(同步)');resolve('resolve 的值');
});promise.then((value) => {console.log('4. .then 回調(異步微任務):', value);
});console.log('3. 同步代碼結束');// 輸出順序:
// 1. 同步代碼開始
// 2. Promise 執行器函數(同步)
// 3. 同步代碼結束
// 4. .then 回調(異步微任務): resolve 的值

4. 異步操作的嵌套

console.log('1. 同步代碼開始');const promise = new Promise((resolve) => {console.log('2. Promise 執行器函數(同步)');setTimeout(() => {console.log('5. setTimeout 回調(異步宏任務)');resolve('resolve 的值');}, 0);
});promise.then((value) => {console.log('6. .then 回調(異步微任務):', value);
});console.log('3. 同步代碼結束');// 輸出順序:
// 1. 同步代碼開始
// 2. Promise 執行器函數(同步)
// 3. 同步代碼結束
// 5. setTimeout 回調(異步宏任務)
// 6. .then 回調(異步微任務): resolve 的值

五、Node.js 與瀏覽器的事件循環差異

特性瀏覽器Node.js
微任務類型PromiseMutationObserverPromiseprocess.nextTick
微任務優先級同層級按注冊順序process.nextTick?優先級最高
宏任務分層單層任務隊列多階段分層(timers → pending → poll → check → close)

六、關鍵總結

  1. 執行順序鐵律
    同步代碼 → 微任務 → 宏任務 → 渲染(瀏覽器)

  2. 微任務優先
    每個宏任務執行完畢后,必須清空所有微任務隊列

  3. 任務嵌套規則

    • 微任務中產生的微任務會繼續在當前批次執行

    • 宏任務中產生的任務會進入下一輪循環

  4. 性能優化建議

    • 避免在微任務中進行耗時操作

    • 合理分配任務類型(密集計算使用宏任務分片)

問答:

  1. 什么是事件循環?

    ?答案?:執行代碼和收集異步任務,在調用棧空閑時,反復調用任務隊列里回調函數執行機制。
  2. 為什么有事件循環?

    ?答案?:JavaScript 是單線程的,為了不阻塞 JS 引擎,設計執行代碼的模型。
  3. JavaScript 內代碼如何執行?

    ?答案?:執行同步代碼,遇到異步代碼交給宿主瀏覽器環境執行 異步有了結果后,把回調函數放入任務隊列排隊 當調用棧空閑后,反復調用任務隊列里的回調函數。
  4. 什么是宏任務?

    ?答案?:瀏覽器執行的異步代碼,例如:JS 執行腳本事件,setTimeout/setInterval,AJAX請求完成事件,用戶交互事件等。
  5. 什么是微任務?

    ?答案?:JS 引擎執行的異步代碼,例如:Promise對象.then()的回調。

示例

回答下面代碼執行順序:

console.log(1)
setTimeout(() => {console.log(2)const p = new Promise(resolve => resolve(3))p.then(result => console.log(result))
}, 0)
const p = new Promise(resolve => {setTimeout(() => {console.log(4)}, 0)resolve(5)
})
p.then(result => console.log(result))
const p2 = new Promise(resolve => resolve(6))
p2.then(result => console.log(result))
console.log(7)

輸出結果:?

1
7
5
6
2
3
4

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/77046.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/77046.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/77046.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java Collection(7)——Iterable接口

1.Iterator接口 1.1 Iterator接口和其他集合類的關系 Java集合類中&#xff0c;Iterable接口屬于頂層接口&#xff0c;除Map接口外&#xff0c;其他都實現了Iterable接口&#xff0c;這意味著它們都可以重寫和使用Iterable接口中的方法 1.2 Iterable接口簡介 在JDK1.7以前&a…

若依微服務版啟動小程序后端

目錄標題 本地啟動&#xff0c;dev對應 nacos里的 xxx-xxx-dev配置文件 本地啟動&#xff0c;dev對應 nacos里的 xxx-xxx-dev配置文件

STM32基礎教程——DMA+ADC多通道

目錄 前言 ?編輯 技術實現 連線圖 代碼實現 技術要點 實驗結果 問題記錄 前言 DMA(Direct Memory Access)直接存儲器存取&#xff0c;用來提供在外設和存儲器 之間或者存儲器和存儲器之間的高速數據傳輸。無需CPU干預&#xff0c;數據可以通過DMA快速地移動&#xff0…

23黑馬產品經理Day01

今天過了一遍23黑馬產品經理的基礎視頻 問題思考維度 抓住核心用戶 為什么需要抓住核心用戶&#xff1f; 主要原因&#xff1a;用戶越來越細分&#xff0c;保持市場競爭力&#xff0c;產品開發推廣更聚焦 做產品為什么要了解用戶&#xff1a;了解用戶的付費點&#xff0c;…

C/C++ 通用代碼模板

? C 語言代碼模板&#xff08;main.c&#xff09; 適用于基礎項目、算法競賽或刷題&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <math.h>// 宏定義區 #define MAX_N 1000 #defi…

【數據結構_7】棧和隊列(上)

一、概念 棧和隊列&#xff0c;也是基于順序表和鏈表實現的 棧是一種特殊的線性表&#xff0c;其只允許在固定的一段進行插入和刪除元素操作。 遵循后進先出的原則 此處所見到的棧&#xff0c;本質上就是一個順序表/鏈表&#xff0c;但是&#xff0c;實在順序表/鏈表的基礎…

git UserInterfaceState.xcuserstate 文件頻繁更新

1> 退出 Xcdoe&#xff0c;打開終端&#xff08;Terminal&#xff09;&#xff0c;進入到你的項目目錄下。 2> 在終端鍵入 git rm --cached <YourProjectName>.xcodeproj/project.xcworkspace/xcuserdata/<YourUsername>.xcuserdatad/UserInterfaceState.x…

【Ai】MCP實戰:手寫 client 和 server [Python版本]

什么是mcp MCP 是一個開放協議&#xff0c;它為應用程序向 LLM 提供上下文的方式進行了標準化。你可以將 MCP 想象成 AI 應用程序的 USB-C 接口。就像 USB-C 為設備連接各種外設和配件提供了標準化的方式一樣&#xff0c;MCP 為 AI 模型連接各種數據源和工具提供了標準化的接口…

ESP8266/32作為AVR編程器(ISP programmer)的使用介紹

ESP8266作為AVR編程器( ISP programmer)的使用介紹 &#x1f33f;ESP8266自帶庫例程&#xff1a;https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266AVRISP&#x1f4cd;支持ESP8266/32的ESP_AVRISP其它開源工程&#xff08;個人沒有再去驗證&#xff09;&…

08-JVM 面試題-mk

文章目錄 1.JVM 的各部分組成2.運行時數據區2.1.什么是程序計數器?2.2.你能給我詳細的介紹Java堆嗎?2.3.能不能解釋一下方法區?2.3.1常量池2.3.2.運行時常量池2.4.什么是虛擬機棧?2.4.1.垃圾回收是否涉及棧內存?2.4.2.棧內存分配越大越好嗎?2.4.3.方法內的局部變量是否線…

Vue3 nextTick

nextTick 是 Vue 中非常重要的一個 API&#xff0c;它允許你在 DOM 更新周期后執行延遲回調。 核心源碼位置 Vue3 的 nextTick 實現主要在 packages/runtime-core/src/scheduler.ts 文件中。 基本實現 const resolvedPromise Promise.resolve() as Promise<any> let …

DISCO:利用大型語言模型提取反事實

DISCO: Distilling Counterfactuals with Large Language Models - ACL Anthologyhttps://aclanthology.org/2023.acl-long.302/ 1. 概述 盡管在自然語言處理(NLP)領域針對各種推理任務取得了巨大進展(Wang 等, 2018, 2019a;Xu 等, 2020),但數據集偏差仍然是構建魯棒模型…

【Django】框架-路由系統核心概念解析

1. 最基本路由關系 路由是URL地址與處理邏輯&#xff08;視圖函數&#xff09;的對應關系。 本質&#xff1a;將用戶請求的URL路徑映射到具體的處理程序&#xff08;如Django視圖函數&#xff09;。 示例&#xff1a; # urls.py urlpatterns [ path(home/, views.home_…

理解 results = model(source, stream=True) 的工作原理和優勢

1. 核心概念解析 (1) streamTrue 的作用 生成器模式&#xff1a;當處理視頻或圖像序列時&#xff0c;streamTrue 會將結果包裝成一個 生成器&#xff08;Generator&#xff09;&#xff0c;逐幀生成 Results 對象&#xff0c;而不是一次性返回所有結果。內存優化&#xff1a;…

重新定義“邊緣”:邊緣計算如何重塑人類與數據的關系

在數字化浪潮中&#xff0c;云計算曾是科技界的寵兒&#xff0c;但如今&#xff0c;邊緣計算正在悄然改變游戲規則。它不僅是一種技術進步&#xff0c;更是對人類與數據關系的一次深刻反思。本文將探討邊緣計算如何從“中心化”走向“分布式”&#xff0c;以及它如何在效率、隱…

MCP 協議知識分享

MCP 協議知識分享 一、MCP 協議概述1.1 定義與背景1.2 核心價值1.3 與傳統 API 的對比 二、技術架構與工作原理2.1 核心組件2.2 通信機制2.3 典型工作流程 三、關鍵技術與應用場景3.1 核心技術3.2 典型應用場景 四、與微軟技術的集成4.1 Azure OpenAI 服務4.2 Playwright MCP 服…

策略模式實現 Bean 注入時怎么知道具體注入的是哪個 Bean?

Autowire Resource 的區別 1.來源不同&#xff1a;其中 Autowire 是 Spring2.5 定義的注解&#xff0c;而 Resource 是 Java 定義的注解 2.依賴查找的順序不同&#xff1a; 依賴注入的功能&#xff0c;是通過先在 Spring IoC 容器中查找對象&#xff0c;再將對象注入引入到當…

Linux》》bash 、sh 執行腳本

通常使用shell去運行腳本&#xff0c;兩種方法 》bash xxx.sh 或 bash “xxx.sh” 、sh xxx.sh 或 sh “xxx.sh” 》bash -c “cmd string” 引號不能省略 我們知道 -c 的意思是 command&#xff0c;所以 bash -c 或 sh -c 后面應該跟一個 command。

【解析】ReentrantLock鎖、Syschronized鎖面試點解析

面試官提問 ● 公平鎖與非公平鎖的區別是什么&#xff1f; ● 什么是可重入鎖&#xff1f; ● 什么是死鎖&#xff0c;怎樣避免死鎖&#xff1f; ● ReentrantLock與Syschronized實現原理是什么&#xff1f;兩者有什么區別&#xff1f; ● 請說明ReentrantLock獲取鎖與釋放…

04.Python代碼NumPy-通過索引或切片來訪問和修改

04.Python代碼NumPy-通過索引或切片來訪問和修改 提示&#xff1a;幫幫志會陸續更新非常多的IT技術知識&#xff0c;希望分享的內容對您有用。本章分享的是Python基礎語法。前后每一小節的內容是存在的有&#xff1a;學習and理解的關聯性&#xff0c;希望對您有用~ python語法…