成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JavaScript 事件循環 —— 微任務 Microtask

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

[[376565]]

微任務(Microtask)

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

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

示例代碼如下:

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

如果你運行它,你會首先看到 code finished,然后才是 promise done。

這很奇怪,因為這個 promise 肯定是一開始就完成的。

為什么 .then 會在之后才被觸發?這是怎么回事?

微任務隊列(Microtask queue)

異步任務需要適當的管理。為此,ECMA 標準規定了一個內部隊列 PromiseJobs,通常被稱為“微任務隊列(microtask queue)”(V8 術語)。

如 規范[1] 中所述:

  • 隊列(queue)是先進先出的:首先進入隊列的任務會首先運行。
  • 只有在 JavaScript 引擎中沒有其它任務在運行時,才開始執行任務隊列中的任務。

或者,簡單地說,當一個 promise 準備就緒時,它的 .then/catch/finally 處理程序(handler)就會被放入隊列中:但是它們不會立即被執行。當 JavaScript 引擎執行完當前的代碼,它會從隊列中獲取任務并執行它。

這就是為什么在上面那個示例中 "code finished" 會先顯示。

 

Promise 的處理程序(handler)總是會經過這個內部隊列。

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

如果執行順序對我們很重要該怎么辦?我們怎么才能讓 code finished 在 promise done 之后運行呢?

很簡單,只需要像下面這樣使用 .then 將其放入隊列:

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

現在代碼就是按照預期執行的。

未處理的 rejection

還記得 使用 promise 進行錯誤處理[2] 一章中的 unhandledrejection 事件嗎?

現在,我們可以確切地看到 JavaScript 是如何發現未處理的 rejection 的。

如果一個 promise 的 error 未被在微任務隊列的末尾進行處理,則會出現“未處理的 rejection”。

正常來說,如果我們預期可能會發生錯誤,我們會在 promise 鏈上添加 .catch 來處理 error:

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

但是如果我們忘記添加 .catch,那么,微任務隊列清空后,JavaScript 引擎會觸發下面這事件:

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

如果我們遲一點再處理這個 error 會怎樣?例如:

  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)); 

現在,如果我們運行上面這段代碼,我們會先看到 Promise Failed!,然后才是 caught。

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

但是現在我們知道了,當微任務隊列中的任務都完成時,才會生成 unhandledrejection:引擎會檢查 promise,如果 promise 中的任意一個出現 "rejected" 狀態,unhandledrejection 事件就會被觸發。

在上面這個例子中,被添加到 setTimeout 中的 .catch 也會被觸發。只是會在 unhandledrejection 事件出現之后才會被觸發,所以它并沒有改變什么(沒有發揮作用)。

總結

Promise 處理始終是異步的,因為所有 promise 行為都會通過內部的 "promise jobs" 隊列,也被稱為“微任務隊列”(V8 術語)。

因此,.then/catch/finally 處理程序(handler)總是在當前代碼完成后才會被調用。

如果我們需要確保一段代碼在 .then/catch/finally 之后被執行,我們可以將它添加到鏈式調用的 .then 中。

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

現代 JavaScript 教程:開源的現代 JavaScript 從入門到進階的優質教程。React 官方文檔推薦,與 MDN 并列的 JavaScript 學習教程[3]。

在線免費閱讀:https://zh.javascript.info

參考資料

 

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

 

責任編輯:武曉燕 來源: 技術漫談
相關推薦

2020-12-29 08:21:03

JavaScript微任務宏任務

2024-10-23 16:02:40

JavaScriptPromiserejection

2021-08-17 09:55:05

JavaScript MicrotaskPromise

2022-06-13 10:24:47

宏任務微任務前端

2021-07-24 11:15:19

開發技能代碼

2023-12-29 12:20:12

$nextTick循環機制循環

2016-09-06 21:23:25

JavaScriptnode異步

2023-04-06 00:22:19

JavaScrip任務開發

2009-03-17 15:36:29

JavaScript循環事件

2022-08-18 11:36:16

可視化JavaScript事件循環

2017-05-02 22:38:44

前端開發JS事件循環機制

2017-03-28 21:25:19

無循環代碼JavaScript

2021-10-22 08:29:14

JavaScript事件循環

2024-08-26 14:52:58

JavaScript循環機制

2021-12-25 22:29:57

Node.js 微任務處理事件循環

2021-10-15 09:56:10

JavaScript異步編程

2020-04-26 08:21:43

javascriptVue

2015-11-06 13:59:01

JavaScript事件處理

2017-01-05 09:07:25

JavaScript瀏覽器驅動

2022-03-11 14:59:21

JavaScript數組字符串
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产激情在线 | 日韩一区二区三区在线视频 | 九九热在线免费视频 | 日韩成人av在线播放 | 成人影院网站ww555久久精品 | 羞羞视频网 | 在线一区二区三区 | 91av免费看 | 91在线精品播放 | av看片| 欧美寡妇偷汉性猛交 | 亚洲一区二区三区四区五区午夜 | 999久久久久久久久6666 | www中文字幕 | 久久三区 | 久久久国产一区二区三区 | 国产精品成人一区二区三区 | 五月精品视频 | 天天影视网天天综合色在线播放 | 日本a视频| 亚洲欧洲一区二区 | 99久久日韩精品免费热麻豆美女 | 欧美激情 一区 | 亚洲国产视频一区二区 | 北条麻妃国产九九九精品小说 | 免费亚洲一区二区 | 色本道| 日本人爽p大片免费看 | 福利久久 | 午夜激情在线视频 | 亚洲一区网站 | 久久aⅴ乱码一区二区三区 亚洲国产成人精品久久久国产成人一区 | 日韩中文字幕在线视频 | 亚洲精品久久久久久下一站 | 日本天堂视频在线观看 | 免费av观看| 欧美成人精品一区二区男人看 | 久草精品视频 | 婷婷在线免费 | a级大片免费观看 | 中文字幕高清av |