摘要:對于引擎來說,兩者獲取堆棧的方式是不同的。對于引擎來說,堆棧信息附加在了函數(shù)所返回的并在鏈中傳遞,這樣函數(shù)也能在需要的時(shí)候獲取堆棧信息。使用可以實(shí)時(shí)監(jiān)控線上應(yīng)用的錯(cuò)誤,并獲取完整的堆棧信息。
譯者按: Async/Await真的只是簡單的語法糖嗎?No!
原文:Asynchronous stack traces: why await beats .then()
作者: Mathias Bynens: Google V8引擎開發(fā)者
譯者:Fundebug
為了保證可讀性,本文采用意譯而非直譯。另外,本文版權(quán)歸原作者所有,翻譯僅用于學(xué)習(xí)。
與直接使用Promise相比,使用Async/Await不僅可以提高代碼的可讀性,同時(shí)也可以優(yōu)化JavaScript引擎的執(zhí)行方式。這篇博客將介紹Async/Await是如何優(yōu)化JavaScript引擎對堆棧信息的處理。
Async/Await與Promise最大區(qū)別在于:await b()會(huì)暫停所在的async函數(shù)的執(zhí)行;而Promise.then(b)將b函數(shù)加入回調(diào)鏈中之后,會(huì)繼續(xù)執(zhí)行當(dāng)前函數(shù)。對于堆棧來說,這個(gè)不同點(diǎn)非常關(guān)鍵。
當(dāng)一個(gè)Promise鏈拋出一個(gè)未處理的錯(cuò)誤時(shí),無論我們使用await b()還是Promise.then(b),JavaScript引擎都需要打印錯(cuò)誤信息及其堆棧。對于JavaScript引擎來說,兩者獲取堆棧的方式是不同的。
Promise.then(b)示例代碼中,函數(shù)c()會(huì)在異步函數(shù)b()成功resolve之后執(zhí)行:
const a = () => { b().then(() => c()); };
當(dāng)調(diào)用a()函數(shù)時(shí),這些事情同步發(fā)生:
b()函數(shù)被調(diào)用,它會(huì)返回一個(gè)Promise,這個(gè)Promise會(huì)在未來的某個(gè)時(shí)刻resolve。
.then()回調(diào)函數(shù)(實(shí)際調(diào)用了c()函數(shù))被添加到回調(diào)鏈。
這樣,a()函數(shù)內(nèi)的代碼就執(zhí)行完了。a()函數(shù)不會(huì)被暫停,因此在異步函數(shù)b()resolve時(shí),a()函數(shù)的作用域已經(jīng)不存在了。假設(shè)b()或者c()拋出了一個(gè)錯(cuò)誤,則堆棧信息中應(yīng)該包含a()函數(shù),因?yàn)樗鼈兌际窃赼()函數(shù)內(nèi)被調(diào)用。對a()函數(shù)的任何引用都不存在了,要如何生成包含a()的堆棧信息呢?
為了解決這個(gè)問題,JavaScript引擎需要做一些額外的工作:它會(huì)及時(shí)記錄并且保存堆棧信息。對于V8引擎來說,堆棧信息附加在了b()函數(shù)所返回的Promise并在Promise鏈中傳遞,這樣c()函數(shù)也能在需要的時(shí)候獲取堆棧信息。
記錄堆棧信息需要時(shí)間,這樣會(huì)降低性能;而保存堆棧信息需要占用額外的內(nèi)存。
使用Fundebug, 可以實(shí)時(shí)監(jiān)控線上應(yīng)用的錯(cuò)誤,并獲取完整的堆棧信息。
Await b()我們可以使用Async/Await實(shí)現(xiàn)同樣的代碼,同步函數(shù)c()會(huì)等到異步函數(shù)b()執(zhí)行結(jié)束之后再執(zhí)行:
const a = async () => { await b(); c(); };
使用await時(shí),無需存儲當(dāng)前的堆棧信息,因?yàn)榇鎯()到a()的指針就足夠了。當(dāng)?shù)却齜()函數(shù)執(zhí)行時(shí),a()函數(shù)被暫停了,因此a()函數(shù)的作用域還在內(nèi)存可以訪問。如果b()函數(shù)拋出一個(gè)錯(cuò)誤,堆棧信息可以通過指針迅速生成。如果c()函數(shù)拋出一個(gè)錯(cuò)誤,堆棧信息也可以像同步函數(shù)一樣生成,因?yàn)閏()函數(shù)是在a()函數(shù)中執(zhí)行的。不論是b()還是c(),我們都不需要去存儲堆棧信息,因?yàn)槎褩P畔⒖梢栽谛枰臅r(shí)候立即生成。而存儲指針,顯然比存儲堆棧更加節(jié)省內(nèi)存。
建議很多ECMAScript語法特性看起來都只是語法糖,其實(shí)并非如此,至少Async/Await絕不僅僅只是語法糖。
為了讓JavaScript引擎處理堆棧的方式性能更高并且更加節(jié)省內(nèi)存,請遵循這些建議:
使用Async/Await,而不是直接使用Promise
使用babel-preset-env,避免Babel不必要地轉(zhuǎn)換Async/Await
盡管V8引擎還沒有實(shí)現(xiàn)這些優(yōu)化,請遵循這些建議。當(dāng)我們?yōu)閂8實(shí)現(xiàn)這些優(yōu)化的時(shí)候,你的程序可以保證最佳的性能。(作者是V8引擎的開發(fā)者)
一般來說,盡量不要去使用Babel轉(zhuǎn)碼器。所有支持Service Workers的瀏覽器都支持Async/Await,因此沒有必要去對Async/Await轉(zhuǎn)碼。這一點(diǎn)對于JavaScript modules via script tag同樣適用。關(guān)于這一點(diǎn),大家可以參考Deploying ES2015+ Code in Production Today。
關(guān)于FundebugFundebug專注于JavaScript、微信小程序、微信小游戲、支付寶小程序、React Native、Node.js和Java實(shí)時(shí)BUG監(jiān)控。 自從2016年雙十一正式上線,F(xiàn)undebug累計(jì)處理了6億+錯(cuò)誤事件,得到了Google、360、金山軟件等眾多知名用戶的認(rèn)可。歡迎免費(fèi)試用!
版權(quán)聲明轉(zhuǎn)載時(shí)請注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2018/07/18/javascript-engine-await-promise/
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/96706.html
摘要:事件循環(huán)從回調(diào)隊(duì)列中獲取并將其推入調(diào)用堆棧。執(zhí)行從調(diào)用堆棧中移除從調(diào)用堆棧中移除快速回顧值得注意的是,指定了事件循環(huán)應(yīng)該如何工作,這意味著在技術(shù)上它屬于引擎的職責(zé)范圍,不再僅僅扮演宿主環(huán)境的角色。 此篇是 JavaScript是如何工作的第四篇,其它三篇可以看這里: JavaScript是如何工作的:引擎,運(yùn)行時(shí)和調(diào)用堆棧的概述! JavaScript是如何工作的:深入V8引擎&編寫...
摘要:函數(shù)會(huì)在之后的某個(gè)時(shí)刻觸發(fā)事件定時(shí)器。事件循環(huán)中的這樣一次遍歷被稱為一個(gè)。執(zhí)行完畢并出棧。當(dāng)定時(shí)器過期,宿主環(huán)境會(huì)把回調(diào)函數(shù)添加至事件循環(huán)隊(duì)列中,然后,在未來的某個(gè)取出并執(zhí)行該事件。 原文請查閱這里,略有改動(dòng)。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現(xiàn)在,我們將會(huì)通過回顧單線程環(huán)境下編程的弊端及如何克服這些困難以創(chuàng)建令人驚嘆...
摘要:拋出的錯(cuò)誤對象會(huì)被方法回調(diào)函數(shù)接收到命令命令后面是一個(gè)對象,返回該對象的結(jié)果。有人將其稱之為宏任務(wù)微任務(wù),定時(shí)器就屬于宏任務(wù)的范疇。 前言 上一篇 前端面試題-JavaScript(一), 感興趣的小伙伴也可以移步這里查看 完整版JavaScript面試題,面試題會(huì)不定期更新加進(jìn)去一些個(gè)人工作中遇到的或者認(rèn)為比較重要的東西,后面會(huì)涉及到前端的各個(gè)方面,感興趣的小伙伴可以關(guān)注哦! 如果文...
摘要:由于是單線程的,這些方法就會(huì)按順序被排列在一個(gè)單獨(dú)的地方,這個(gè)地方就是所謂執(zhí)行棧。事件隊(duì)列每次僅執(zhí)行一個(gè)任務(wù),在該任務(wù)執(zhí)行完畢之后,再執(zhí)行下一個(gè)任務(wù)。 Event Loop 是 JavaScript 異步編程的核心思想,也是前端進(jìn)階必須跨越的一關(guān)。同時(shí),它又是面試的必考點(diǎn),特別是在 Promise 出現(xiàn)之后,各種各樣的面試題層出不窮,花樣百出。這篇文章從現(xiàn)實(shí)生活中的例子入手,讓你徹底理解 E...
閱讀 801·2021-10-09 09:44
閱讀 705·2019-08-30 13:55
閱讀 3165·2019-08-29 15:07
閱讀 3231·2019-08-29 13:09
閱讀 2422·2019-08-29 11:10
閱讀 1301·2019-08-26 14:05
閱讀 3606·2019-08-26 13:57
閱讀 2216·2019-08-23 16:42