Javascript中的宏任務與微任務

事件循環

JavaScript 語言的一大特點就是單線程,也就是說,同一個時間只能做一件事。為了協調事件、用戶交互、腳本、UI 渲染和網絡處理等行為,防止主線程的不阻塞,Event Loop 的方案應用而生。Event Loop 包含兩類:一類是基于 Browsing Context,一種是基于 Worker。二者的運行是獨立的,也就是說,每一個 JavaScript 運行的"線程環境"都有一個獨立的 Event Loop,每一個 Web Worker 也有一個獨立的 Event Loop。

本文所涉及到的事件循環是基于 Browsing Context。

任務隊列

根據規范,事件循環是通過任務隊列的機制來進行協調的。一個 Event Loop 中,可以有一個或者多個任務隊列(task queue),一個任務隊列便是一系列有序任務(task)的集合;每個任務都有一個任務源(task source),源自同一個任務源的 task 必須放到同一個任務隊列,從不同源來的則被添加到不同隊列。setTimeout/Promise 等API便是任務源,而進入任務隊列的是他們指定的具體執行任務。

在事件循環中,每進行一次循環操作稱為 tick,每一次 tick 的任務處理模型是比較復雜的,但關鍵步驟如下:

在此次 tick 中選擇最先進入隊列的任務(oldest task),如果有則執行(一次)
檢查是否存在 Microtasks,如果存在則不停地執行,直至清空 Microtasks Queue
更新 render
主線程重復執行上述步驟

在上訴tick的基礎上需要了解幾點:

JS分為同步任務和異步任務
同步任務都在主線程上執行,形成一個執行棧
主線程之外,事件觸發線程管理著一個任務隊列,只要異步任務有了運行結果,就在任務隊列之中放置一個事件。
一旦執行棧中的所有同步任務執行完畢(此時JS引擎空閑),系統就會讀取任務隊列,將可運行的異步任務添加到可執行棧中,開始執行。

宏任務

(macro)task,可以理解是每次執行棧執行的代碼就是一個宏任務(包括每次從事件隊列中獲取一個事件回調并放到執行棧中執行)。

瀏覽器為了能夠使得JS內部(macro)task與DOM任務能夠有序的執行,會在一個(macro)task執行結束后,在下一個(macro)task 執行開始前,對頁面進行重新渲染,流程如下:

(macro)task->渲染->(macro)task->…
宏任務包含:

script(整體代碼)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 環境)
微任務

microtask,可以理解是在當前 task 執行結束后立即執行的任務。也就是說,在當前task任務后,下一個task之前,在渲染之前。

所以它的響應速度相比setTimeout(setTimeout是task)會更快,因為無需等渲染。也就是說,在某一個macrotask執行完后,就會將在它執行期間產生的所有microtask都執行完畢(在渲染前)。

微任務包含:

Promise.then
Object.observe
MutationObserver
process.nextTick(Node.js 環境)
運行機制

在事件循環中,每進行一次循環操作稱為 tick,每一次 tick 的任務處理模型是比較復雜的,但關鍵步驟如下:

執行一個宏任務(棧中沒有就從事件隊列中獲取)
執行過程中如果遇到微任務,就將它添加到微任務的任務隊列中
宏任務執行完畢后,立即執行當前微任務隊列中的所有微任務(依次執行)
當前宏任務執行完畢,開始檢查渲染,然后GUI線程接管渲染
渲染完畢后,JS線程繼續接管,開始下一個宏任務(從事件隊列中獲取)

如圖:
jstask.png

實例講解
實例1
setTimeout(function(){console.log('定時器開始啦')});new Promise(function(resolve){console.log('馬上執行for循環啦');for(var i = 0; i < 10000; i++){i == 99 && resolve();}}).then(function(){console.log('執行then函數啦')});console.log('代碼執行結束');//馬上執行for循環啦 //代碼執行結束 //執行then函數啦 //定時器開始啦

首先執行script下的宏任務,遇到setTimeout,將其放到宏任務的【隊列】里

遇到 new Promise直接執行,打印"馬上執行for循環啦"

遇到then方法,是微任務,將其放到微任務的【隊列里】

打印 “代碼執行結束”

本輪宏任務執行完畢,查看本輪的微任務,發現有一個then方法里的函數, 打印"執行then函數啦"

到此,本輪的event loop 全部完成。

下一輪的循環里,先執行一個宏任務,發現宏任務的【隊列】里有一個 setTimeout里的函數,執行打印"定時器開始啦"

實例2
async function async1() {console.log( 'async1 start' )await async2()console.log( 'async1 end' )
}
async function async2() {console.log( 'async2' )
}
async1()
console.log( 'script start' )//async1 start
//async2
//script start
//async1 end

一旦遇到 await 就立刻讓出線程,阻塞后面的代碼

等候之后,對于 await 來說分兩種情況

不是 promise 對象
如果不是 promise,await會阻塞后面的代碼,先執行async外面的同步代碼,同步代碼執行完畢后,在回到async內部,把promise的東西,作為await表達式的結果

是promise對象
如果它等到的是一個 promise 對象,await 也會暫停async后面的代碼,先執行async外面的同步代碼,等著 Promise 對象 fulfilled,然后把 resolve 的參數作為 await 表達式的運算結果。

如果一個 Promise 被傳遞給一個 await 操作符,await 將等待 Promise 正常處理完成并返回其處理結果。

實例3
       new Promise( ( resolve, reject ) => {console.log( "promise1" )resolve()} ).then( () => {console.log( 1 )} ).then( () => {console.log( 2 )} ).then( () => {console.log( 3 )} )new Promise( ( resolve, reject ) => {console.log( "promise2" )resolve()} ).then( () => {console.log( 4 )} ).then( () => {console.log( 5 )} ).then( () => {console.log( 6 )} )//1-4-2-5-3-6

先執行同步代碼 promise1, promise2,此時微任務有兩個任務 log(1)和log(4)

執行完log(1)和log(4)此時任務中有log(2)和log(5)兩個微任務

執行log(2)和log(5)此時任務中有log(3)和log(6)兩個微任務

連續的幾個then()回調,并不是連續的創建了一系列的微任務并推入微任務隊列,因為then()的返回值必然是一個Promise,而后續的then()是上一步then()返回的Promise的回調

實例4
setTimeout(() => console.log('setTimeout1'), 0);  //1宏任務
setTimeout(() => {								//2宏任務console.log('setTimeout2');Promise.resolve().then(() => {console.log('promise3');Promise.resolve().then(() => {console.log('promise4');})console.log(5)})setTimeout(() => console.log('setTimeout4'), 0);  //4宏任務
}, 0);
setTimeout(() => console.log('setTimeout3'), 0);  //3宏任務
Promise.resolve().then(() => {//1微任務console.log('promise1');
})//promise1
//setTimeout1
//setTimeout2
//promise3
//5
//promise4
//setTimeout3
//setTimeout4

在這里插入圖片描述

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

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

相關文章

購買Zoho CRM系統要花多少錢?

相信對CRM系統有過了解的人都知道&#xff0c;CRM系統的價格取決于功能需求&#xff0c;用戶數量&#xff0c;部署方式&#xff0c;定制開發等因素。Zoho CRM是全球領先的云CRM系統&#xff0c;自2005年推出以來&#xff0c;累計服務25萬企業&#xff0c;那么Zoho CRM系統的價格…

python批量修改文件夾下的后綴名

python批量修改文件夾下的后綴名 &#xff08;所有的.txt結尾的文件&#xff0c;替換成.py結尾&#xff09; 1、需要將某個文件夾下所有的.txt結尾的文件&#xff0c;替換成.py結尾 2、Python代碼&#xff1a; import os# 指定需要更改文件的目錄 dir_path D:/study/py/4#…

Vatee萬騰數字引領未來:vatee科技力量的獨特路徑

在當今數字化浪潮的推動下&#xff0c;Vatee萬騰以其卓越的科技力量&#xff0c;正引領著未來的數字化時代&#xff0c;描繪著一條獨特的發展路徑。通過持續創新、前瞻思維和對技術的深度理解&#xff0c;Vatee萬騰正在為未來的科技發展創造新的可能性&#xff0c;塑造著數字引…

微信開放平臺Android平臺應用簽名怎么填寫

winR 輸入cmd 進到本地簽名文件的目錄下 輸入 keytool -list -v -keystore <keystore文件路徑> -alias <別名>請將 <keystore文件路徑> 替換為您的密鑰庫文件&#xff08;通常是 .jks 或 .keystore 文件&#xff09;的路徑&#xff0c;而 <別名> 則是…

Speaker Verification,聲紋驗證詳解——語音信號處理學習(九)

參考文獻&#xff1a; Speaker Verification嗶哩嗶哩bilibili 2020 年 3月 新番 李宏毅 人類語言處理 獨家筆記 聲紋識別 - 16 - 知乎 (zhihu.com) (2) Meta Learning – Metric-based (1/3) - YouTube 如何理解等錯誤率(EER, Equal Error Rate)&#xff1f;請不要只給定義 - 知…

oracle數據庫巡檢常見腳本-系列二

簡介 作為數據庫管理員&#xff08;DBA&#xff09;&#xff0c;定期進行數據庫的日常巡檢是非常重要的。以下是一些原因&#xff1a; 保證系統的穩定性&#xff1a;通過定期巡檢&#xff0c;DBA可以發現并及時解決可能導致系統不穩定的問題&#xff0c;如性能瓶頸、資源利用率…

libcurl curlcode 35問題解決

libcurl code 35 定義&#xff1a; SSL CONNECT ERROR 我這里問題情況會出現以下兩種 SSL證書認證&#xff0c;可以添加相應的頭取消或是添加驗證 curl_easy_setopt(curl, CURLOPT_URL, combinePath.c_str());curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);curl_easy_setop…

人工智能:讓生活更便捷、更智能——探討人工智能在生活中的作用與挑戰

文章目錄 前言人工智能的定義與分類人工智能的領域一、智能語音助手改變日常生活二、智能駕駛帶來出行革命三、人工智能在醫療健康領域的應用四、教育領域的人工智能創新 人工智能的應用生活方面的影響工作方面的影響 應對AI帶來的挑戰后記 前言 人工智能相關的領域&#xff0…

Python基于機器學習模型LightGBM進行水電站流量入庫預測項目源碼+數據集+模型,含項目報告

1.前言 該文檔主要是介紹通過機器學習模型LightGBM進行水電站流量入庫預測。 對于水電站來說&#xff0c;發電是主要經濟效益來源&#xff0c;而水就是生產的原料。對進入水電站水庫的入庫流量進行精準預測&#xff0c;能夠幫助水電站對防洪、發電計劃調度工作進行合理安排&…

java常見數值類型取值范圍/ int short long BigInteger取值范圍

文章目錄 一、各類型取值范圍 一、各類型取值范圍 以下整理java中常用的數值類型取值范圍。 類型字節大小最小值最大值取值范圍byte8bit-128127-128到127short16bit-2 15 ^{15} 152 15 ^{15} 15-1-32768-32767int32bit-2 31 ^{31} 312 31 ^{31} 31 -1-2,147,483,648 到 2,147…

女娃娃就要打扮,就要時刻保持美麗

超足充絨量&#xff0c;細膩柔軟 上身效果很棒保暖性也很強 無論是日常出行還是戶外活動 穿這件羽絨服都妥妥的 簡約時尚的色彩搭配 使它在寒冷的冬季 既能保暖又能展現個人品味哦&#xff01;

家電回收小程序,省心省力的好幫手

隨著科技的不斷進步和人們生活水平的提高&#xff0c;家用電器已經成為我們日常生活中不可或缺的一部分。然而&#xff0c;隨著時間的推移&#xff0c;一些家電產品逐漸被淘汰或閑置下來。那么&#xff0c;如何處理這些閑置家電呢&#xff1f; 此時&#xff0c;一款家電回收小程…

創建vue項目體驗

文章目錄 使用vue-cli創建vue項目創建出的項目目錄結構配置router 運行問題router未找到eslint報錯 首頁顯示單頁面內容替換 使用vue-cli創建vue項目 安裝vue-cli&#xff0c;創建基本項目 選擇步驟 一般創建成功后&#xff0c;提示使用下面的指令運行demo npm run serve創建…

【開源項目】熱點監測降級框架Akali源碼解讀

項目地址 https://gitee.com/dromara/Akali 項目介紹 Akali&#xff08;阿卡麗&#xff09;是一個輕量級本地化熱點檢測/降級框架&#xff0c;適用于大流量場景&#xff0c;可輕松解決業務中超高流量的并發查詢等場景。并且接入和使用極其簡單&#xff0c;10秒鐘即可接入使用&a…

Visual NLP:圖像信息自動提取的未來

本文旨在以簡單的方式解釋 Visual NLP 的關鍵概念&#xff0c;讓你了解 Visual NLP 的含義、它的用例是什么、如何使用它以及為什么它是構建自動提取管道的未來 。 NSDT在線工具推薦&#xff1a; Three.js AI紋理開發包 - YOLO合成數據生成器 - GLTF/GLB在線編輯 - 3D模型格式在…

微信小程序-空值操作符

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 空值合并操作符&#xff08;??&#xff09; 空值合并操作符&#xff08;??&#xff09; 在編寫代碼時&#xff0c;如果某個屬性不為 null 和 undefined&#x…

C++ 函數、數組、指針、輸入輸出、日期時間

一、C函數&#xff1a; 函數是一組執行一個任務的語句。每個C程序至少有一個函數&#xff0c;即主函數main()。函數有很多叫法&#xff0c;比如方法、子例程或程序等等。函數聲明告訴編譯器函數的名稱、返回類型和參數。函數定義提供了函數的實際主體。 return_type function…

一站式解決Mac音視頻轉換需求——Xilisoft Video Converter Ultimate for Mac

在數字化時代&#xff0c;音視頻的應用越來越廣泛&#xff0c;不同的設備和平臺對音視頻格式的要求也不盡相同。因此&#xff0c;如何找到一款功能強大、易于操作的音視頻轉換軟件成為了Mac用戶的迫切需求。而Xilisoft Video Converter Ultimate for Mac&#xff08;曦力音視頻…

4.18每日一題(極坐標累次積分到直角坐標累次積分的轉換)

注&#xff1a;rdr化為直角坐標以后r直接消去了&#xff0c;不需要計算

可編程交流回饋式負載箱在電源設備中的應用

可編程交流回饋式負載箱可以用于測試電源設備的輸出能力&#xff0c;通過在負載箱中設置不同的負載條件&#xff0c;可以模擬不同的工作負載情況&#xff0c;從而測試電源設備在不同負載下的輸出能力和穩定性。這對于電源設備的設計和生產非常重要&#xff0c;可以幫助制造商評…