JS異步堆棧追蹤之為什么await勝過(guò)Promise
async/await和Promise的根本區(qū)別在于await fn()暫停當(dāng)前函數(shù)的執(zhí)行,而promise.then(fn)在將fn調(diào)用添加到回調(diào)鏈后,繼續(xù)執(zhí)行當(dāng)前函數(shù)。
const fn = () => console.log(’hello’)const a = async () => { await fn() // 暫停 fn 的執(zhí)行}// 調(diào)用 a 時(shí),才恢復(fù) fn 的執(zhí)行a() // 'hello'const promise = Promise.resolve()// 將 fn 添加到回調(diào)鏈后,繼續(xù)執(zhí)行 fnpromise.then(fn) // 'hello'
在堆棧追蹤的上下文中,這種差異非常顯著。
當(dāng)一個(gè)Promise鏈(無(wú)論是否脫糖化)在任何時(shí)候拋出一個(gè)未經(jīng)處理的異常時(shí),JavaScript引擎都會(huì)顯示一條錯(cuò)誤信息和(希望)記錄一個(gè)有用的堆棧追蹤。
作為一名開(kāi)發(fā)人員,無(wú)論您使用的是普通的Promise還是async await,您都會(huì)期望這樣。
Promise想象一個(gè)場(chǎng)景,當(dāng)對(duì)異步函數(shù)b的調(diào)用解析時(shí),調(diào)用函數(shù)c:
const b = () => Promise.resolve()const a = () => { b().then(() => c())}
當(dāng)調(diào)用a時(shí),將同步發(fā)生以下情況:
b被調(diào)用并返回一個(gè)Promise,該P(yáng)romise將在將來(lái)某個(gè)時(shí)刻解決。 .then回調(diào)(實(shí)際上是調(diào)用c())被添加到回調(diào)鏈中( V8 術(shù)語(yǔ)中,[…]被添加為解析處理程序)。之后,我們完成了在函數(shù)a的主體中執(zhí)行代碼。a永遠(yuǎn)不會(huì)被掛起,當(dāng)對(duì)b的異步調(diào)用解析時(shí),上下文已經(jīng)消失了。
想象一下如果b(或c)異步拋出異常會(huì)發(fā)生什么?理想情況下,堆棧追蹤應(yīng)該包括a,因?yàn)閎(或c)是從那里調(diào)用的,對(duì)吧?既然我們不在參考a了 ,那怎樣能做到呢?
為了讓它工作,JavaScript 引擎需要在上面的步驟之外做一些事情:它在有機(jī)會(huì)的時(shí)候捕獲并存儲(chǔ)堆棧追蹤。
在V8中,堆棧追蹤附加到b返回的Promise。當(dāng)Promise實(shí)現(xiàn)時(shí),堆棧追蹤將被傳遞,以便c可以根據(jù)需要使用它。
b()[a] -> b().then()[a] -> c[a?:a]
捕獲堆棧追蹤需要時(shí)間(即降低性能);存儲(chǔ)這些堆棧追蹤需要內(nèi)存。
async/await下面是同樣的程序,使用async/await而不是Promise編寫:
const b = () => Promise.resolve()const a = async () => { await b() c()}
使用await,即使在await調(diào)用中不收集堆棧追蹤,我們也可以恢復(fù)調(diào)用鏈。
這是可能的,因?yàn)閍被掛起,正在等待b解決。如果b拋出異常,則可以按需以這種方式重建堆棧追蹤。
如果c拋出異常,堆棧追蹤可以像同步函數(shù)那樣構(gòu)造,因?yàn)榘l(fā)生這種情況時(shí),我們?nèi)栽赼上下文中。
通過(guò)遵循以下建議,使 JavaScript 引擎能夠以更高效的方式處理堆棧追蹤:
偏好async/await勝過(guò)Promise。 使用 @babel/preset env避免不必要的async/await傳輸。以上就是JS異步堆棧追蹤之為什么await勝過(guò)Promise的詳細(xì)內(nèi)容,更多關(guān)于Javascript的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. python中scrapy處理項(xiàng)目數(shù)據(jù)的實(shí)例分析2. js抽獎(jiǎng)轉(zhuǎn)盤實(shí)現(xiàn)方法分析3. IntelliJ IDEA導(dǎo)入jar包的方法4. Python requests庫(kù)參數(shù)提交的注意事項(xiàng)總結(jié)5. 教你在 IntelliJ IDEA 中使用 VIM插件的詳細(xì)教程6. SpringBoot參數(shù)校驗(yàn)與國(guó)際化使用教程7. iOS實(shí)現(xiàn)點(diǎn)贊動(dòng)畫特效8. python操作mysql、excel、pdf的示例9. 通過(guò)Python pyecharts輸出保存圖片代碼實(shí)例10. vue-electron中修改表格內(nèi)容并修改樣式
