簡述js的事件循環以及宏任務和微任務

前言

JavaScript中,任務被分為同步任務和異步任務。

  • 同步任務:這些任務在主線程上順序執行,不會進入任務隊列,而是直接在主線程上排隊等待執行。每個同步任務都會阻塞后續任務的執行,直到它自身完成。常見的同步任務包括頁面的初始化、DOM操作和某些計算任務。
  • 異步任務:與同步任務不同,異步任務不直接進入主線程執行,而是被放入任務隊列(task queue)中。只有當主線程空閑時,才會從任務隊列中取出任務來執行。異步任務不會阻塞主線程的執行。根據任務類型,異步任務又被分為宏任務微任務

一、事件循環是什么?

  • JavaScript 的事件循環(Event Loop)是其運行時環境(如瀏覽器或 Node.js處理異步操作和回調的一種機制。它允許 JavaScript 在不阻塞單線程執行的情況下,響應用戶交互、處理網絡請求、定時器回調等異步事件

二、事件循環的基本基本概念和工作原理

1. 調用棧(Call Stack

JavaScript 引擎有一個調用棧,用于跟蹤函數調用的順序。當一個函數調用發生時,它會被推入調用棧中。當函數執行完畢后,它會被從調用棧中彈出。

2. 任務隊列(Task Queue):

當異步操作(如 setTimeout、setInterval、DOM 事件、Promise.resolve().then() 等)完成時,它們會生成一個任務(task)(簡單理解為任務就是回調函數),并將這個任務放入相應的任務隊列中等待執行。

  • 這些任務隊列包括宏任務隊列(macrotask queue)和微任務隊列(microtask queue
  • 宏任務隊列主要存放 script(全局任務)、setTimeoutsetIntervalsetImmediateNode.js 環境)等;微任務隊列主要存放 Promise 的回調函數、MutationObserver(瀏覽器環境)等。
3. 事件循環:

事件循環的基本順序是:

  1. 當調用棧為空時(即沒有正在執行的函數),事件循環會查看任務隊列。
  2. 事件循環會率先查看微任務隊列。如果微任務隊列中有任務,它會將任務逐個取出并執行,直到微任務隊列為空。
  3. 然后,事件循環會查看宏任務隊列。如果宏任務隊列中有任務,它會將任務取出并執行。在執行宏任務的過程中,可能會產生新的微任務,這些微任務會被添加到微任務隊列的末尾。
  4. 當一個宏任務執行完畢后,事件循環會再次查看微任務隊列并執行其中的任務,這個過程會一直重復,直到所有的任務都被執行完畢。
  5. 這個過程會持續進行,形成了一個循環,這就是所謂的“事件循環”。

三、宏任務和微任務?

  • JavaScript的事件循環中,任務的執行被分為兩種主要的類別:宏任務(MacroTask)和微任務(MicroTask)。這兩種任務類型在事件循環中的處理順序和方式有所不同。
1. 宏任務(MacroTask

宏任務通常包括:

  • script(整體代碼)
  • setTimeout
  • setInterval
  • setImmediateNode.js 環境)
  • I/O
  • UI渲染(瀏覽器會在每次事件循環結束后進行UI渲染)
  • MessageChannel(消息通道)
  • postMessage(一些HTML5 API使用)
  • requestAnimationFrame(瀏覽器用于定時執行動畫)

宏任務創建后會被放入宏任務隊列中,JavaScript引擎會在當前執行棧清空后,從宏任務隊列中取出隊首任務執行。

2. 微任務(MicroTask

微任務通常包括:

  • Promise.then()Promise.catch()
  • MutationObserverHTML5API,用于監聽DOM變更)
  • process.nextTickNode.js環境)
    與宏任務不同,微任務是在當前宏任務執行完成后立即執行的。在JavaScript引擎執行完一個宏任務后,它會先查看微任務隊列,并執行所有的微任務,直到微任務隊列為空。然后,它會繼續取出并執行下一個宏任務。這個過程會不斷重復,形成JavaScript的事件循環。

執行順序
考慮以下的示例:

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'); // 同步任務
盡管setTimeout的延遲被設置為0,但它的回調仍然會在所有的微任務之后執行。因此,上述代碼的輸出順序為:script start  
script end  
promise1  
promise2  
setTimeout
這是因為當JavaScript引擎執行到setTimeout時,它會將回調函數放入宏任務隊列,并繼續執行后續的代碼。當執行到Promise.then()時,它會將回調函數放入微任務隊列。在所有宏任務代碼執行完畢后,JavaScript引擎會先執行所有的微任務,然后再從宏任務隊列中取出并執行下一個宏任務。

四、練習

  1. 練習一:
  console.log('Start'); // 同步任務// 宏任務1setTimeout(() => {console.log('Timeout callback'); // 同步任務Promise.resolve().then(() => {console.log('Promise 1'); //  微任務1Promise.resolve().then(() => {console.log('Promise 2'); //  微任務2Promise.resolve().then(() => {console.log('Promise 3'); //  微任務3執行完執行下一個宏任務});});});}, 0);// 宏任務2setTimeout(() => {console.log('Timeout222 callback'); // 6}, 0);
  1. 練習二:
  //  開啟一個微任務,當dom修改時觸發const observer = new MutationObserver(function (mutationsList, observer) {console.log(mutationsList, observer)});const config = { attributes: true, childList: true, subtree: true };console.log('script start'); // 同步任務 1  (function () {console.log('自執行函數 '); // 同步任務 2})()// 宏任務2setTimeout(function () {Promise.resolve().then(function () {var element = document.getElementById('app');observer.observe(element, config);var child = document.getElementById('child');element.innerHTML = '<p>這是一段新的HTML內容。</p>';console.log('promise11'); // 同步任務  Promise.resolve().then(() => {console.log('promise11 callback 1'); // (3) 微任務  });Promise.resolve().then(() => {console.log('promise11 callback 2'); // (3) 微任務  });})console.log('setTimeout'); // 同步任務  }, 0);// 宏任務3setTimeout(() => {console.log(111);})Promise.resolve().then(function () {console.log('promise1'); // 微任務1  Promise.resolve().then(() => {console.log('promise1 callback 1'); // 微任務1-2  });Promise.resolve().then(() => {console.log('promise1 callback 2'); // 微任務 1-3  });}).then(function () {console.log('promise2'); // 微任務2  // 宏任務4setTimeout(() => {console.log('微任務內的宏任務'); // 宏任務隊列4Promise.resolve().then(() => {console.log('微任務2 promise callback'); // 微任務隊列4 });})Promise.resolve().then(() => {console.log('promise2 callback 1'); // 微任務2-1  });Promise.resolve().then(() => {console.log('promise2 callback 2'); // 微任務2-2  });})console.log('script end'); // 同步任務3// 執行同步任務,當遇到異步宏任務放入宏任務隊列,異步微任務放入微任務隊列// 所以執行順序// script start// 自執行函數// script end// promise1// promise1 callback 1// promise1 callback 2// promise2// promise2 callback 1// promise2 callback 2// ---宏任務2// setTimeout// promise11// MutationObserver// promise11 callback 1// promise11 callback 2// ---宏任務3// 111// ---宏任務4// 微任務內的宏任務// 微任務2 promise callback
  1. 練習三:script整體為何是宏任務
// 宏任務一
<script>console.log('script1') // 同步// 宏任務三setTimeout(() => {console.log('setTimeout1');// 宏任務五setTimeout(() => {console.log('setTimeout3');})})// 微任務Promise.resolve().then(() => {console.log('promise1');})
</script>// 宏任務二
<script>console.log('script2') // 同步// 宏任務四setTimeout(() => {console.log('setTimeout2');// 宏任務六setTimeout(() => {console.log('setTimeout4');})})// 微任務Promise.resolve().then(() => {console.log('promise2');})
</script>可以看出來script相當于setTimeOut開啟宏任務列表,執行完當前宏任務去執行微任務,微任務執行完畢,執行宏任務二,以此類推所以輸出結果:
script1
promise1
script2
promise2
setTimeout1
setTimeout2
setTimeout3
setTimeout4

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

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

相關文章

【機器學習】機器學習與大型預訓練模型的前沿探索:跨模態理解與生成的新紀元

&#x1f512;文章目錄&#xff1a; &#x1f4a5;1.引言 ?2.跨模態理解與生成技術概述 &#x1f6b2;3.大型預訓練模型在跨模態理解與生成中的應用 &#x1f6f4;4.前沿探索與挑戰并存 &#x1f44a;5.未來趨勢與展望 &#x1f4a5;1.引言 近年來&#xff0c;機器學習領…

著名書法家王杰寶做客央視頻《筆墨寫人生》藝壇人物經典訪談節目

印象網北京訊&#xff08;張春兄、馮愛云&#xff09;展示藝術風采&#xff0c;構建時代精神。5月25日&#xff0c;著名書法家、羲之文化傳承人王杰寶&#xff0c;做客央視頻《筆墨寫人生》藝壇人物經典訪談節目&#xff0c;與中央電視臺紀錄頻道主持人姚文倩一起&#xff0c;分…

MyBatis 中的動態 SQL 的相關使用方法(Javaee/MyBatis)

MyBatis 的動態 SQL 是一種強大的特性&#xff0c;它可以讓你在 XML 映射文件內&#xff0c;根據不同的條件編寫不同的 SQL 語句。MyBatis 動態 SQL 主要元素有&#xff1a; <if>: 根據提供的條件來動態拼接 SQL。 接口定義 Integer insertUserByCondition(UserInfo u…

c++ list容器

std::list 是 C 標準庫中的一個雙向鏈表容器。與 std::vector&#xff08;動態數組&#xff09;和 std::deque&#xff08;雙端隊列&#xff09;不同&#xff0c;std::list 的元素在內存中不是連續存儲的&#xff0c;而是分散存儲并通過節點進行連接。這使得 std::list 在插入和…

SpringBoot 集成 ChatGPT(附實戰源碼)

建項目 項目結構 application.properties openai.chatgtp.modelgpt-3.5-turbo openai.chatgtp.api.keyREPLACE_WITH_YOUR_API_KEY openai.chatgtp.api.urlhttps://api.openai.com/v1/chat/completionsopenai.chatgtp.max-completions1 openai.chatgtp.temperature0 openai.cha…

全局平均池化筆記

全局平均池化&#xff08;Global Average Pooling, GAP&#xff09;是一種用于卷積神經網絡&#xff08;CNN&#xff09;中的池化操作&#xff0c;其主要作用和優點包括&#xff1a; 減少參數數量&#xff1a;全局平均池化層將每個特征圖通過取其所有元素的平均值&#xff0c;壓…

ubuntu安裝yum方法【最新可用】

一、安裝命令 在根目錄&#xff08;root&#xff09;下執行 sudo apt-get install build-essential sudo apt-get install yum二、出錯處理 1、E: Package yum has no installation candidate 解決&#xff1a;更換鏡像源&#xff0c;找到自己的系統版本用vim進行更換&#xff…

make是什么

make是什么工具 make是一個自動化編譯工具,它本身并沒有編譯和鏈接的功能,而是用類似于批處理的方式——通過makefile文件中指示的依賴關系,調用makefile文件中使用的命令來完成編譯和鏈接的。makefile文件中記錄了源代碼文件之間的依賴關系,并說明了如何編譯各個源代碼文…

GmSSL3.X編譯iOS和Android動態庫

一、環境準備 我用的Mac電腦編譯&#xff0c;Xcode版本15.2&#xff0c;安卓的NDK版本是android-ndk-r21e。 1.1、下載國密源碼 下載最新的國密SDK源碼到本地。 1.2、安裝Xcode 前往Mac系統的AppStore下載安裝最新Xcode。 1.3、安卓NDK下載 下載NDK到本地&#xff0c;選…

Protobuf - 語法、字段使用規則、注意事項

目錄 前言 一、Protobuf 基本語法 1.1、Protoc 版本 1.2、文件格式配置 1.3、消息字段規則 1.3.1、字段數據類型 1.3.2、字段修飾規則 1.3.3、消息類型定義 1.3.4、enum 類型 1.3.5、Any 類型 1.3.6、oneof 類型 1.3.7、map 類型 1.3.8、默認值 1.3.9、更新消息…

css設置文字在固定寬度中等距分開(僅限于單行文本)

一、要實現的效果&#xff1a; 二、代碼 要在CSS中設置文本在一個固定寬度的容器中等距分開&#xff0c; 可以使用text-align: justify;屬性&#xff0c;它可以讓文本兩端對齊&#xff0c;看起來就像是等距分開的。 但是要注意&#xff0c;單獨使用text-align:justify;只能對單…

機器學習 - 模型訓練

機器學習&#xff08;Machine Learning&#xff0c;ML&#xff09;是利用計算機算法和統計模型&#xff0c;使計算機系統在沒有明確編程的情況下執行特定任務的過程。機器學習的整個過程可以分為以下幾個主要步驟&#xff1a; 訓練步驟 問題定義與需求分析 目標設定&#xff1…

【Qt】Qt多元素控件深入解析與實戰應用:列表(QListWidget)、表格(QTableWidget)與樹形(QTreeWidget)結構

文章目錄 前言&#xff1a;Qt中多元素控件&#xff1a;1. List Widget1.1. 代碼示例: 使用 ListWidget 2.Table Widget2.1. 代碼示例: 使用 QTableWidget 3. Tree Widget3.1. 代碼示例: 使用 QTreeWidget 總結&#xff1a; 前言&#xff1a; 在Qt框架中&#xff0c;用戶界面的…

2024.5.25

package com.Swork.file;import java.io.File; import java.io.IOException; import java.util.Date;public class Demo1 {public static void main(String[] args) {//1,構造文件對象System.out.println("1,構造文件對象");File file new File("D://Work//Fil…

C語言內存函數超詳細講解

個人主頁&#xff1a;C忠實粉絲 歡迎 點贊&#x1f44d; 收藏? 留言? 加關注&#x1f493;本文由 C忠實粉絲 原創 C語言內存函數超詳細講解 收錄于專欄【C語言學習】 本專欄旨在分享學習C語言學習的一點學習筆記&#xff0c;歡迎大家在評論區交流討論&#x1f48c; 目錄 1. m…

C++面向對象程序設計-北京大學-郭煒【課程筆記(十一)】

C面向對象程序設計-北京大學-郭煒【課程筆記&#xff08;十一&#xff09;】 1、string&#xff08;重要知識點&#xff09;1.2、string的賦值和鏈接1.3、比較string1.4、子串1.5、交換string1.6、尋找string中的字符1.7、刪除string中的字符1.8、替換string中的字符1.9、在str…

leetcode119-Pascal‘s Triangle II

題目 給定一個非負索引 rowIndex&#xff0c;返回「楊輝三角」的第 rowIndex 行。 在「楊輝三角」中&#xff0c;每個數是它左上方和右上方的數的和。 示例 1: 輸入: rowIndex 3 輸出: [1,3,3,1] 分析 楊輝三角每位數字就是上一行同一列&#xff0b;上一行前一列的和&#…

結構體;結構成員訪問操作符

結構體&#xff1a; 雖然c語言已經提供了內置類型&#xff0c;比如&#xff1a;char、short、int、long等&#xff0c;但還是不夠用&#xff0c;就好比我描述一個人&#xff0c;我需要描述他的身高&#xff0c;體重&#xff0c;年齡&#xff0c;名字等信息&#xff0c…

微軟密謀超級AI大模型!LangChain帶你輕松玩轉大模型開發

此前&#xff0c;據相關媒體報道&#xff0c;微軟正在研發一款名為MAI-1的最新AI大模型&#xff0c;其參數規模或將達5000億以上&#xff0c;遠超此前微軟推出的相關開源模型&#xff0c;其性能或能與谷歌的Gemini 1.5、Anthropic的Claude 3和OpenAI的GPT-4等知名大模型相匹敵。…

Linux文本處理三劍客(詳解)

一、文本三劍客是什么&#xff1f; 1. 對于接觸過Linux操作系統的人來說&#xff0c;應該都聽過說Linux中的文本三劍客吧&#xff0c;即awk、grep、sed&#xff0c;也是必須要掌握的Linux命令之一&#xff0c;三者都是用來處理文本的&#xff0c;但側重點各不相同&#xff0c;a…