自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript 事件循環(huán) —— 微任務(wù) Microtask

開(kāi)發(fā) 前端
Promise 的處理程序(handlers).then、.catch 和 .finally 都是異步的。即便一個(gè) promise 立即被 resolve,.then、.catch 和 .finally 下面 的代碼也會(huì)在這些處理程序(handler)之前被執(zhí)行。

[[376565]]

微任務(wù)(Microtask)

Promise 的處理程序(handlers).then、.catch 和 .finally 都是異步的。

即便一個(gè) promise 立即被 resolve,.then、.catch 和 .finally 下面 的代碼也會(huì)在這些處理程序(handler)之前被執(zhí)行。

示例代碼如下:

  1. let promise = Promise.resolve(); 
  2.  
  3. promise.then(() => alert("promise done!")); 
  4.  
  5. alert("code finished"); // 這個(gè) alert 先顯示 

如果你運(yùn)行它,你會(huì)首先看到 code finished,然后才是 promise done。

這很奇怪,因?yàn)檫@個(gè) promise 肯定是一開(kāi)始就完成的。

為什么 .then 會(huì)在之后才被觸發(fā)?這是怎么回事?

微任務(wù)隊(duì)列(Microtask queue)

異步任務(wù)需要適當(dāng)?shù)墓芾?。為此,ECMA 標(biāo)準(zhǔn)規(guī)定了一個(gè)內(nèi)部隊(duì)列 PromiseJobs,通常被稱(chēng)為“微任務(wù)隊(duì)列(microtask queue)”(V8 術(shù)語(yǔ))。

如 規(guī)范[1] 中所述:

  • 隊(duì)列(queue)是先進(jìn)先出的:首先進(jìn)入隊(duì)列的任務(wù)會(huì)首先運(yùn)行。
  • 只有在 JavaScript 引擎中沒(méi)有其它任務(wù)在運(yùn)行時(shí),才開(kāi)始執(zhí)行任務(wù)隊(duì)列中的任務(wù)。

或者,簡(jiǎn)單地說(shuō),當(dāng)一個(gè) promise 準(zhǔn)備就緒時(shí),它的 .then/catch/finally 處理程序(handler)就會(huì)被放入隊(duì)列中:但是它們不會(huì)立即被執(zhí)行。當(dāng) JavaScript 引擎執(zhí)行完當(dāng)前的代碼,它會(huì)從隊(duì)列中獲取任務(wù)并執(zhí)行它。

這就是為什么在上面那個(gè)示例中 "code finished" 會(huì)先顯示。

 

Promise 的處理程序(handler)總是會(huì)經(jīng)過(guò)這個(gè)內(nèi)部隊(duì)列。

如果有一個(gè)包含多個(gè) .then/catch/finally 的鏈,那么它們中的每一個(gè)都是異步執(zhí)行的。也就是說(shuō),它會(huì)首先進(jìn)入隊(duì)列,然后在當(dāng)前代碼執(zhí)行完成并且先前排隊(duì)的處理程序(handler)都完成時(shí)才會(huì)被執(zhí)行。

如果執(zhí)行順序?qū)ξ覀兒苤匾撛趺崔k?我們?cè)趺床拍茏?code finished 在 promise done 之后運(yùn)行呢?

很簡(jiǎn)單,只需要像下面這樣使用 .then 將其放入隊(duì)列:

  1. Promise.resolve() 
  2.   .then(() => alert("promise done!")) 
  3.   .then(() => alert("code finished")); 

現(xiàn)在代碼就是按照預(yù)期執(zhí)行的。

未處理的 rejection

還記得 使用 promise 進(jìn)行錯(cuò)誤處理[2] 一章中的 unhandledrejection 事件嗎?

現(xiàn)在,我們可以確切地看到 JavaScript 是如何發(fā)現(xiàn)未處理的 rejection 的。

如果一個(gè) promise 的 error 未被在微任務(wù)隊(duì)列的末尾進(jìn)行處理,則會(huì)出現(xiàn)“未處理的 rejection”。

正常來(lái)說(shuō),如果我們預(yù)期可能會(huì)發(fā)生錯(cuò)誤,我們會(huì)在 promise 鏈上添加 .catch 來(lái)處理 error:

  1. let promise = Promise.reject(new Error("Promise Failed!")); 
  2. promise.catch(err => alert('caught')); 
  3.  
  4. // 不會(huì)運(yùn)行:error 已經(jīng)被處理 
  5. window.addEventListener('unhandledrejection', event => alert(event.reason)); 

但是如果我們忘記添加 .catch,那么,微任務(wù)隊(duì)列清空后,JavaScript 引擎會(huì)觸發(fā)下面這事件:

  1. let promise = Promise.reject(new Error("Promise Failed!")); 
  2.  
  3. // Promise Failed! 
  4. window.addEventListener('unhandledrejection', event => alert(event.reason)); 

如果我們遲一點(diǎn)再處理這個(gè) error 會(huì)怎樣?例如:

  1. let promise = Promise.reject(new Error("Promise Failed!")); 
  2. setTimeout(() => promise.catch(err => alert('caught')), 1000); 
  3.  
  4. // Error: Promise Failed! 
  5. window.addEventListener('unhandledrejection', event => alert(event.reason)); 

現(xiàn)在,如果我們運(yùn)行上面這段代碼,我們會(huì)先看到 Promise Failed!,然后才是 caught。

如果我們并不了解微任務(wù)隊(duì)列,我們可能會(huì)想:“為什么 unhandledrejection 處理程序(handler)會(huì)運(yùn)行?我們已經(jīng)捕獲(catch)并處理了 error!”

但是現(xiàn)在我們知道了,當(dāng)微任務(wù)隊(duì)列中的任務(wù)都完成時(shí),才會(huì)生成 unhandledrejection:引擎會(huì)檢查 promise,如果 promise 中的任意一個(gè)出現(xiàn) "rejected" 狀態(tài),unhandledrejection 事件就會(huì)被觸發(fā)。

在上面這個(gè)例子中,被添加到 setTimeout 中的 .catch 也會(huì)被觸發(fā)。只是會(huì)在 unhandledrejection 事件出現(xiàn)之后才會(huì)被觸發(fā),所以它并沒(méi)有改變什么(沒(méi)有發(fā)揮作用)。

總結(jié)

Promise 處理始終是異步的,因?yàn)樗?promise 行為都會(huì)通過(guò)內(nèi)部的 "promise jobs" 隊(duì)列,也被稱(chēng)為“微任務(wù)隊(duì)列”(V8 術(shù)語(yǔ))。

因此,.then/catch/finally 處理程序(handler)總是在當(dāng)前代碼完成后才會(huì)被調(diào)用。

如果我們需要確保一段代碼在 .then/catch/finally 之后被執(zhí)行,我們可以將它添加到鏈?zhǔn)秸{(diào)用的 .then 中。

在大多數(shù) JavaScript 引擎中(包括瀏覽器和 Node.js),微任務(wù)(microtask)的概念與“事件循環(huán)(event loop)”和“宏任務(wù)(macrotasks)”緊密相關(guān)。由于這些概念跟 promise 沒(méi)有直接關(guān)系,所以我們將在 圖解 JavaScript 事件循環(huán):微任務(wù)和宏任務(wù) 一文中對(duì)它們進(jìn)行介紹。

現(xiàn)代 JavaScript 教程:開(kāi)源的現(xiàn)代 JavaScript 從入門(mén)到進(jìn)階的優(yōu)質(zhì)教程。React 官方文檔推薦,與 MDN 并列的 JavaScript 學(xué)習(xí)教程[3]。

在線(xiàn)免費(fèi)閱讀:https://zh.javascript.info

參考資料

 

[1]規(guī)范: https://tc39.github.io/ecma262/#sec-jobs-and-job-queues[2]使用 promise 進(jìn)行錯(cuò)誤處理: https://zh.javascript.info/promise-error-handling[3]React 官方文檔推薦,與 MDN 并列的 JavaScript 學(xué)習(xí)教程: https://zh-hans.reactjs.org/docs/getting-started.html#javascript-resources

 

責(zé)任編輯:武曉燕 來(lái)源: 技術(shù)漫談
相關(guān)推薦

2020-12-29 08:21:03

JavaScript微任務(wù)宏任務(wù)

2024-10-23 16:02:40

JavaScriptPromiserejection

2021-08-17 09:55:05

JavaScript MicrotaskPromise

2021-07-24 11:15:19

開(kāi)發(fā)技能代碼

2022-06-13 10:24:47

宏任務(wù)微任務(wù)前端

2023-12-29 12:20:12

$nextTick循環(huán)機(jī)制循環(huán)

2016-09-06 21:23:25

JavaScriptnode異步

2023-04-06 00:22:19

JavaScrip任務(wù)開(kāi)發(fā)

2009-03-17 15:36:29

JavaScript循環(huán)事件

2022-08-18 11:36:16

可視化JavaScript事件循環(huán)

2017-05-02 22:38:44

前端開(kāi)發(fā)JS事件循環(huán)機(jī)制

2017-03-28 21:25:19

無(wú)循環(huán)代碼JavaScript

2021-10-22 08:29:14

JavaScript事件循環(huán)

2024-08-26 14:52:58

JavaScript循環(huán)機(jī)制

2021-12-25 22:29:57

Node.js 微任務(wù)處理事件循環(huán)

2021-10-15 09:56:10

JavaScript異步編程

2020-04-26 08:21:43

javascriptVue

2017-01-05 09:07:25

JavaScript瀏覽器驅(qū)動(dòng)

2015-11-06 13:59:01

JavaScript事件處理

2022-03-11 14:59:21

JavaScript數(shù)組字符串
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)