面試中常見的問題:JavaScript 宏任務與微任務,包教包會

事件循環Event Loop

我們都知道,JavaScript 是一種單線程的編程語言,簡單的說就是:js只有一條通道,那么在任務多的情況下,就會出現擁擠的情況,這種情況下就產生了 ‘多線程’ ,但是這種“多線程”是通過單線程模仿的,也就是假的。

這意味著它一次只能執行一個任務。但是,通過事件循環(Event Loop)機制,可以處理異步操作并確保程序的高效運行。理解事件循環對于我們前端開發者來說至關重要!

事件循環的基本概念

事件循環的核心在于任務隊列(Task Queue),它負責管理和調度各種任務的執行。任務分為兩類:宏任務微任務

事件循環的執行步驟

事件循環的基本執行步驟如下:

  1. 執行一個宏任務(例如,從頭到尾運行一個 script)。
  2. 執行所有的微任務(一直執行,直到微任務隊列為空)。
  3. 更新渲染(如果需要)。
  4. 繼續執行下一個宏任務。

看不懂沒關系,結合下面的例子就能明白了!

宏任務和微任務詳解

基于上面的基礎知識,我們詳細介紹下宏任務和微任務

為什么要區分宏任務和微任務?

(1)js是單線程的,但是分同步異步
(2)微任務和宏任務皆為異步任務,它們都屬于一個隊列
(3)宏任務一般是:script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate(Node.js 環境)
(4)微任務:Promise.then、Object.observe、MutationObserver、process.nextTick(Node.js 環境)
(5)先執行同步再執行異步,異步遇到微任務,先執行微任務,執行完后如果沒有微任務,就執行下一個宏任務,如果有微任務,就按順序一個一個執行微任務

宏任務、微任務有哪些?

  • 宏任務一般是:script、setTimeout、setInterval、postMessage、MessageChannel、setImmediate(Node.js 環境)
  • 微任務:Promise.then、Object.observe、MutationObserver、process.nextTick(Node.js 環境)

宏任務、微任務是怎么執行的?

簡單來說,宏任務、微任務的執行順序是:先執行同步代碼,異步任務放入任務隊列中,當所有同步代碼執行完畢后,先執行微任務在執行宏任務。

接下來,我們將通過很多例子,幫助大家深入了解

基本事件循環

setTimeout(function(){console.log(1);
});
new Promise(function(resolve){		    console.log(2);resolve();
}).then(function(){		    console.log(3);
}).then(function(){console.log(4)
}); 		
console.log(5);
// 2 5 3 4 1

分析

  1. setTimout是異步宏任務,放入宏任務隊列中
  2. new Promise在實例化的過程中所執行的代碼都是同步進行的,所以輸出2
  3. Promise.then是異步微任務,將其放入微任務隊列中
  4. 遇到同步任務console.log(5);輸出5;主線程中同步任務執行完
  5. 從微任務隊列中取出任務到主線程中,輸出3、 4,微任務隊列為空
  6. 從宏任務隊列中取出任務到主線程中,輸出1,宏任務隊列為空
console.log(1)
setTimeout(function() {console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {resolve(4)
})
p.then(data => {console.log(data)
})
console.log(3)
//1,3,4,2
  • 遇到同步任務console.log(1);輸出1;
  • 遇到setTimeout 異步宏任務,放入宏任務隊列中;
  • 遇到 Promise,new Promise在實例化的過程中所執行的代碼都是同步進行的,但由于new Promise沒有輸出事件,所以接著執行遇到.then;
  • 執行.then,異步微任務,被分發到微任務Event Queue中;
  • 遇到同步任務console.log(3);輸出3;
  • 主線程中同步任務執行完,從微任務隊列中取出任務到主線程中,p.then 輸出4,微任務執行完畢,任務隊列為空;
  • 開始執行宏任務setTimeout 輸出2,宏任務隊列為空;

嵌套的宏任務與微任務

console.log('腳本開始')
setTimeout(() => {console.log('這是setTimeout1-------------');Promise.resolve().then(() => {console.log('這是promise1');});
}, 0);setTimeout(() => {console.log('這是setTimeout2');
}, 0);Promise.resolve().then(() => {console.log('這是promise2');
});console.log('腳本結束');

執行順序:

  1. console.log('腳本開始') —— 同步代碼,立即執行。
  2. 第一個 setTimeout 回調注冊到宏任務隊列。
  3. 第二個 setTimeout 回調注冊到宏任務隊列。
  4. Promise 回調注冊到微任務隊列。
  5. console.log('腳本結束') —— 同步代碼,立即執行。
  6. 當前宏任務執行完畢,執行微任務隊列:
    • console.log('這是promise2')
  7. 微任務執行完畢,執行第一個宏任務隊列:
    • console.log('這是setTimeout1-------------')
    • 注冊新的微任務 console.log('這是promise1') 到微任務隊列。
  8. 執行微任務隊列:
    • console.log('這是promise1')
  9. 執行第二個宏任務隊列:
    • console.log('這是setTimeout2')

輸出結果:

腳本開始
腳本結束
這是promise2
這是setTimeout1-------------
這是promise1
這是setTimeout2

多個微任務

console.log('腳本開始');setTimeout(() => {console.log('這是setTimeout');
}, 0);Promise.resolve().then(() => {console.log('這是promise1');
}).then(() => {console.log('這是promise2');
}).then(() => {console.log('這是promise3');
});console.log('腳本結束');

執行順序:

  1. console.log('腳本開始') —— 同步代碼,立即執行。
  2. setTimeout 回調注冊到宏任務隊列。
  3. Promise 回調注冊到微任務隊列。
  4. console.log('腳本結束') —— 同步代碼,立即執行。
  5. 當前宏任務執行完畢,執行微任務隊列:
    • console.log('這是promise1')
    • 注冊新的微任務 console.log('這是promise2') 到微任務隊列。
    • 執行微任務隊列:
      • console.log('這是promise2')
      • 注冊新的微任務 console.log('這是promise3') 到微任務隊列。
      • 執行微任務隊列:
        • console.log('這是promise3')
  6. 微任務執行完畢,執行宏任務隊列:
    • console.log('這是setTimeout')

輸出結果:

腳本開始
腳本結束
這是promise1
這是promise2
這是promise3
這是setTimeout

總結

通過這些詳細的例子,相信大家對宏任務與微任務一定有了更深入的了解。希望本文對大家有幫助~感謝支持

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

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

相關文章

【LeetCode102.二叉樹的層序遍歷】vs.【LeetCode103.二叉樹的鋸齒形層序遍歷】

題目鏈接 LeetCode102.二叉樹的層序遍歷:102. 二叉樹的層序遍歷 - 力扣(LeetCode)LeetCode103.二叉樹的鋸齒形層序遍歷:103. 二叉樹的鋸齒形層序遍歷 - 力扣(LeetCode) 實現思路 定義一個隊列&#xff0…

Redis On-CPU Profiling定位瓶頸到可視化火焰圖

1 . 前置檢查:確認 CPU 真的是瓶頸 在正式打性能“補丁”前,務必跑一遍系統級健康核對表(推薦 Brendan Greg 的 USE Method):資源關注指標常用工具CPUUtil/Idle、RunQueuetop、vmstat、sar內存Fault、Swap、Cache Miss…

未來趨勢:AI與量子計算對服務器安全的影響

隨著技術的飛速發展,人工智能(AI)和量子計算正在深刻改變信息技術的各個領域。特別是在服務器安全領域,這兩項技術既帶來了新的可能性,也帶來了前所未有的挑戰。本文將探討AI和量子計算技術對服務器安全的影響&#xf…

markdown學習筆記(個人向) Part.1

markdown學習筆記(個人向) Part.1 1. 推薦插件 markdown: 安裝支持markdown的插件; markdown-preview-github-styles: 可以將VS Code上默認的markdown預覽樣式修改成github上常用的形式,很大程度上提高文件…

ZooKeeper 實現分布式鎖

1. 分布式鎖概述 在分布式系統中,為了保證共享資源在并發訪問下的數據一致性,需要引入分布式鎖。分布式鎖是一種在分布式環境下控制多個進程對共享資源進行互斥訪問的機制。它與單機環境下的鎖(如Java中的synchronized或Lock)不同…

Linux線程——基礎全解

一、什么是線程(Thread)?? 定義:線程是程序執行的最小單位。即線程(Thread)是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。一個進程可以并發多…

Java基礎--封裝+static

目錄 什么是封裝? 什么是訪問限定符? static靜態修飾符 用static修飾的類變量或類方法的注意事項: 什么是封裝? 封裝是面向對象的三大特性之一,指的是將一個類中的實現細節進行隱藏,對外只提供一些開放…

DAY 51 復習日

作業:day43的時候我們安排大家對自己找的數據集用簡單cnn訓練,現在可以嘗試下借助這幾天的知識來實現精度的進一步提高import torch import torch.nn as nn import torch.nn.functional as F import torchvision import torchvision.transforms as trans…

針對網絡爬蟲的相關法律法規整理

在中國,網絡爬蟲的法律法規涉及多個層面,包括個人信息保護、數據安全、網絡安全、知識產權、反不正當競爭等。以下是詳細的法律法規分析及合規指南: 1. 核心法律法規及適用場景? ??(1)《民法典》——隱私權與個人信…

1.1_5_2 計算機網絡的性能指標(下)

繼續來看計算機網絡的性能指標,接下來我們探討時延,時延帶寬積和往返時延,以及信道利用率這幾個性能指標。 首先來看時延這個性能指標,英文叫delay,也有的教材,把它翻譯為延遲。所謂的時延,就是…

PP-OCRv2:超輕OCR系統的萬能包

PP-OCRv2:超輕OCR系統的萬能包摘要光學字符識別(OCR)系統已廣泛應用于多種場景,但設計兼顧精度與效率的OCR系統仍具挑戰性。我們此前提出的超輕量OCR系統PP-OCR在平衡兩者方面取得進展。本文進一步提出PP-OCRv2,通過五…

常見的軟件版本開源協議

開源軟件許可證核心指南 一、許可證基礎分類 1. 寬松型許可證(Permissive) 核心特征:允許閉源衍生,僅保留版權聲明適用場景:商業集成、快速開發代表協議: 📜 MIT 📜 Apache 2.0 &…

基于FPGA的一維序列三次樣條插值算法verilog實現,包含testbench

目錄 1.前言 2.算法運行效果圖預覽 3.算法運行軟件版本 4.部分核心程序 5.算法仿真參數 6.算法理論概述 7.參考文獻 8.算法完整程序工程 1.前言 三次樣條插值是一種在數據擬合和信號處理中廣泛應用的技術,它通過構造分段三次多項式來逼近給定的離散數據點&a…

RAG 之 Prompt 動態選擇的三種方式

“如果我有5個prompt模板,我想只選擇一個每次都自動五選一能做到嗎怎么做?” 完全可以做到。這在復雜的RAG或Agentic工作流中是一個非常普遍且關鍵的需求,通常被稱為“條件路由(Conditional Routing)”或“動態調度&am…

【ROS2 自動駕駛學習】02-安裝ROS2及其配套工具

目錄 一、設置語言環境 二、添加存儲庫 三、添加軟件源 四、安裝ROS2 五、配置環境 六、測試ROS2 七、安裝一些工具 7.1 terminator 7.2 colcon工具 7.3 tf工具 7.4 joint-state-publisher工具 7.5 urdf 八、安裝三方庫 8.1 Eigen 8.2 yaml-cpp 8.3 matplotl…

系統學習Python——并發模型和異步編程:基礎知識

分類目錄:《系統學習Python》總目錄 并行是并發的一種特殊情況。**所有并行系統都是并發的,但不是所有并發系統都是并行的。**在21世紀初,我們可以使用單核設備在GNU Linux上同時處理100個進程。一臺擁有4個CPU核的現代筆記本計算機&#xff…

睿爾曼系列機器人——以創新驅動未來,重塑智能協作新生態(下)

在智能制造與人工智能深度融合的當下,機器人技術正經歷從 “功能替代” 到 “價值共創” 的深刻躍遷。睿爾曼,作為全球超輕量仿人機械臂領域的先行者,始終秉持 “讓機器人觸手可及” 的使命,憑借底層技術的突破性進展,…

表征工程(Representation Engineering, RepE)

表征工程(Representation Engineering, RepE) 近年來,表征工程(Representation Engineering, RepE)在提升AI系統透明度和可控性方面取得了顯著進展。 一、大模型可解釋性與可控性的突破 核心論文:《Representation Engineering: A Top-Down Approach to AI Transparen…

國產ARM+FPGA工業開發平臺——GM-3568JHF

一、引言 隨著物聯網和國產替代需求的快速發展,嵌入式系統面臨計算性能與硬件靈活性的雙重挑戰。GM-3568JHF開發板基于國產“ARMFPGA”異構架構,結合瑞芯微RK3568J處理器與紫光同創Logos-2 FPGA芯片,支持國產自主操作系統,滿足通…

RISCV Linux 虛擬內存精講系列一 Sv39

筆者認為,Linux 操作系統(Operating System)最核心的機制是虛擬內存(Virtual Memory)。因為,操作系統主要作用是將硬件環境抽象起來,給在其中運行的應用(Applications)提…