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

答網(wǎng)友問:Await 一個 Promise 對象到底發(fā)生了什么

云計算 云原生
讓我們看一遍 Node.js 官網(wǎng)對 event-loop 的描述。它強(qiáng)調(diào)了一個重點(diǎn):JS code 是以單線程方式被執(zhí)行的。

大家好,我是二哥。

前兩篇文章發(fā)出來后,有一些網(wǎng)友在后臺咨詢我一些問題,我把它們歸總羅列在一起。這篇文章既是答網(wǎng)友問也是對前兩篇的補(bǔ)充和復(fù)習(xí)。

先放下前兩篇的鏈接。

?圖解 Node.js 的核心 event-loop?

??多圖剖析公式 async=Promise+Generator+自動執(zhí)行器??

圖片

圖 1:async 函數(shù)代碼示例

問 0:上一篇所提到的 generator 和自動執(zhí)行器是運(yùn)行在不同的線程里面嗎?

答 0:無論是 generator 還是自動執(zhí)行器,都是在 event-loop 線程也就是運(yùn)行 JS code 的主線程里面運(yùn)行的。再強(qiáng)調(diào)一遍:它倆不是在兩個線程里面運(yùn)行的。

讓我們再看一遍 Node.js 官網(wǎng)對 event-loop 的描述。它強(qiáng)調(diào)了一個重點(diǎn):JS code 是以單線程方式被執(zhí)行的。

The event loop is what allows Node.js to perform non-blocking I/O operations  despite the fact that JavaScript is single-threaded  by offloading operations to the system kernel whenever possible.

問 1:await p 這條語句產(chǎn)生了異步請求了嗎?

答 1:不,它沒有。await 只是在等待 p 狀態(tài)的改變,無論狀態(tài)是從 pending 變成 resolved 還是從 pending 變?yōu)?rejected 。

問 2:那異步請求是什么時候產(chǎn)生的?

答 2:是在 Promise 的 executor 里面,執(zhí)行 setTimeout 時產(chǎn)生的。

?下文把 new Promise() 時傳遞進(jìn)去的 callback (resolve, reject)=>{ /* your code */} 稱為 executor 。其中參數(shù) resolve 和 reject 是由 Promise 自己實(shí)現(xiàn)的。需要注意的是這個 executor 是在 new Promise() 的時候,立即執(zhí)行的。

假如我們在 executor 里面執(zhí)行的是 fs.read(fd[, options], callback) 這樣的語句,那類似地,異步請求是在調(diào)用 fs.read() 時產(chǎn)生的。?

問 3:p 狀態(tài)改變后,為什么通過 resolve(200) 傳遞的 200 會變成變量 res 的求值結(jié)果?

答 3:這就是為什么說我們需要了解 await 背后的實(shí)現(xiàn)原理。我們借助圖 2 和圖 4 來復(fù)習(xí)一下。

如圖 2 所示,async 函數(shù)首先轉(zhuǎn)換成了 generator 函數(shù)。但 generator 函數(shù)自己是不能自動運(yùn)行的,所以得搭配一個自動執(zhí)行器,驅(qū)動它往前走。自動執(zhí)行器如同慈愛的媽媽,而 generator 就像那個懵懂的幼兒。小孩子每走一段路都會停下來,回頭看看在他身后寸步不離的媽媽,得到媽媽的鼓勵或者獎勵后,再走向下一個目標(biāo)。

圖片

圖 2:async 函數(shù)轉(zhuǎn)換成 generator 函數(shù)示例

在講解圖 4 之前,還是有必要再次復(fù)習(xí)兩個重要的概念:yield 表達(dá)式和 yield 語句。如圖 3 所示:

  • a+b 是表達(dá)式,它的求值結(jié)果影響到的是 { value: xxx, done: xxx } 中的 value 屬性,而 { value: xxx, done: xxx } 是調(diào)用者通過迭代器調(diào)用 next() 方法的返回值 。
  • yield a+b 是 yield 語句,調(diào)用者可以通過給 next() 方法傳實(shí)參來影響 yield 語句的返回值。比如 next(200) 則會使得變量 a1 為 200 。

圖 3 還畫出了一個重要的地方:generator 函數(shù)執(zhí)行的暫停點(diǎn):在 yield 表達(dá)式求值結(jié)束之后,但 yield 語句返回之前。

圖片

圖 3:yield 表達(dá)式和 yield 語句對比

為了更好更清晰地回答問題 3,二哥給大家畫了圖 4 。

?這一步開始通過執(zhí)行器調(diào)用 generator。

② 雖然對 generator 真正的調(diào)用發(fā)生在這里,但 generator 函數(shù)在 ② 這步其實(shí)什么都沒有做,只是立即返回了一個迭代器。

③ 自動執(zhí)行器從這里開始進(jìn)入驅(qū)動 generator 模式。③ 這一步?jīng)]有給形參 data? 賦值,因?yàn)槲覀儾荒茉诘谝淮螆?zhí)行  g.next() 的時候給它注入一個值。

④ 這一步每調(diào)用一次  g.next() 就會使得 generator 從上次暫停于 yield 的位置開始運(yùn)行,直到再次遇到 yield 。

⑤ 所以第一次對  g.next() 調(diào)用使得左側(cè) generator 函數(shù)從函數(shù)起始位置一直運(yùn)行直到遇到 yield 。

我們看到 ⑤ 所標(biāo)識出來的代碼執(zhí)行過程其實(shí)是創(chuàng)建了一個 Promise 對象,且在 Promise 的 executor 里面設(shè)置了一個 1s 鐘的定時器。注意,這個 executor 是在創(chuàng)建 Promise 對象時立即執(zhí)行的,不過 ⑦ 處的代碼要等到 1s 之后才會執(zhí)行。

⑥ generator 函數(shù)暫停之前,先會將 yield 表達(dá)式的求值結(jié)果通過 { value: xxx, done: xxx} 返回給  g.next() 調(diào)用方,也即右圖 ④ 位置。 

所以你一定猜到了,右圖 ④ 位置的變量 result 為 { value: p, done: false} 。這里的 p 就是 ⑤ 執(zhí)行過程中產(chǎn)生的 Promise 對象。

通過這樣的方式,Promise 對象在 generator 函數(shù)和自動執(zhí)行器之間流轉(zhuǎn)。真是一個巧妙的過程。

那么你在右側(cè) ⑧ 處看到 result.value.then(callback) 這樣的語句就不會感到納悶了,這是 Promise 的標(biāo)準(zhǔn)用法。當(dāng) p 的狀態(tài)變成 resolved 后,⑧ 處的 callback 自然就會得到運(yùn)行的機(jī)會了。

⑦ 1s 很快,滴答一下過去后,resolve(200) 得以運(yùn)行。它的運(yùn)行使得 p 的狀態(tài)變成 resolved,所以在  ⑧ 處耐心等待的 callback 開始了它的工作。

⑧ 是的,這個時候 data 的值為 200 。這是再自然不過的事,如果你對 Promise 的使用了然于胸的話。

⑨ 自動執(zhí)行器又一次執(zhí)行 next(data)? 。不過這一次給它傳了一個實(shí)參 200 。所以這一次 ④ 處執(zhí)行的代碼變?yōu)椋?nbsp;g.next(200) 。

⑩ 自動執(zhí)行器執(zhí)行  g.next(200) 必然會驅(qū)使 generator 函數(shù)動身繼續(xù)往前趕路。

還記得 generator 函數(shù)上次停在哪里休息的嗎?對,左側(cè) ⑤ 處箭頭所指的位置。generator 函數(shù)恢復(fù)運(yùn)行后干的第一件事就是對 yield 語句求值。

如果像   g.next()?  這樣驅(qū)動它的話,yield 語句返回的是 undefined 。不過這次我們不一樣,因?yàn)槲覀儓?zhí)行的是  g.next(200) 。很巧妙,傳給 next() 的實(shí)參  200 作為 yield 語句的返回值賦值給了左側(cè)變量 res? 。

圖片

圖 4:generator + 自動執(zhí)行器細(xì)節(jié)圖

讓我們再回頭看下圖 1 的示例代碼,我們來做個總結(jié):

  1. await p 語句是個糖衣,它包裹的是 yield p 語句 + 自動執(zhí)行器。
  2. 所謂 await p 暫停并不是說主線程執(zhí)行  JS  code 暫停了。相反主線程還在繼續(xù)執(zhí)行其它的 JS code 。
  3. await 是在等待 p 的狀態(tài)發(fā)生變化。這個等待時間有多長?這完全取決于創(chuàng)建 p 的時候,  executor 里面何時會調(diào)用 resolve() 或 reject() 。
  4. 執(zhí)行 await p 語句的時候,無論 p 的狀態(tài)是否已經(jīng)發(fā)生了變化,執(zhí)行到 await p 都會導(dǎo)致 V8 engine 轉(zhuǎn)而去自動執(zhí)行器里面執(zhí)行。這是 yield p 語句使然。
  5. 動執(zhí)行器如同一個如影隨形的媽媽,她拿到 p 之后,會耐心地等待,直到得到 p 狀態(tài)改變后的 value 。最后再通過 g.next(value) 把 value 返回給它摯愛的 generator 函數(shù)。

圖片

圖 5:同圖 1

責(zé)任編輯:姜華 來源: 二哥聊云原生
相關(guān)推薦

2020-08-17 12:47:07

Mozilla裁員瀏覽器

2019-11-12 14:41:41

Redis程序員Linux

2010-02-07 09:00:29

AndroidLinux Kerne

2020-09-01 11:40:01

HTTPJavaTCP

2022-05-26 23:36:36

SQLMySQL數(shù)據(jù)

2020-10-09 08:59:55

輸入網(wǎng)址解密

2015-07-03 09:27:43

網(wǎng)絡(luò)閏秒

2021-02-25 10:02:32

開機(jī)鍵Linux內(nèi)存

2019-12-10 09:42:57

OOM運(yùn)維內(nèi)存

2017-04-11 13:54:49

HTTPURLHTML

2025-04-27 08:11:26

2010-06-04 10:12:43

馬化騰

2022-05-31 13:58:09

MySQL查詢語句

2024-11-04 09:10:00

2017-04-10 15:57:10

AsyncAwaitPromise

2024-11-04 08:10:00

2019-08-26 09:35:25

命令ping抓包

2018-12-24 09:47:06

2020-07-28 23:22:35

制造業(yè)工業(yè)物聯(lián)網(wǎng)IIOT

2021-04-11 10:40:16

Git軟件開發(fā)
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 久久久www成人免费无遮挡大片 | 亚洲成人av | 999久久久| 精品视频免费在线 | 久久亚洲一区二区三区四区 | 国产一区二区三区在线 | 色婷婷久久久久swag精品 | 亚洲成人在线免费 | 91麻豆精品国产91久久久更新资源速度超快 | 一区二区三区日本 | 久久小视频 | 天天爽天天干 | 久久久久久久一区 | 天天干夜夜操 | 日本一级淫片免费啪啪3 | 极品在线| 日韩福利片 | 日韩精品成人一区二区三区视频 | 国产精品日韩欧美一区二区 | 秋霞在线一区 | 99视频在线播放 | 日本黄色一级视频 | 亚洲欧洲色视频 | 久久久久国产精品午夜一区 | www312aⅴ欧美在线看 | 91精品久久久 | 成人影院网站ww555久久精品 | 国产精品一区二区无线 | 国产精品69毛片高清亚洲 | 精品一区二区三区四区 | 一区二区三区免费在线观看 | 国产国拍亚洲精品av | 日韩av在线播 | 婷婷综合色 | 一区二区三区av | 国产欧美在线视频 | 三级视频国产 | 亚洲视频欧美视频 | 羞羞在线视频 | 精品视频一区二区三区 | 国内自拍偷拍 |