JS异步堆栈追踪之为什么await胜过Promise


Posted in Javascript onApril 28, 2021

概述

async/await和Promise的根本区别在于await fn()暂停当前函数的执行,而promise.then(fn)在将fn调用添加到回调链后,继续执行当前函数。

const fn = () => console.log('hello')
const a = async () => {
  await fn() // 暂停 fn 的执行
}
// 调用 a 时,才恢复 fn 的执行
a() // "hello"

const promise = Promise.resolve()
// 将 fn 添加到回调链后,继续执行 fn
promise.then(fn) // "hello"

在堆栈追踪的上下文中,这种差异非常显著。

当一个Promise链(无论是否脱糖化)在任何时候抛出一个未经处理的异常时,JavaScript引擎都会显示一条错误信息和(希望)记录一个有用的堆栈追踪。

作为一名开发人员,无论您使用的是普通的Promise还是async await,您都会期望这样。

Promise

想象一个场景,当对异步函数b的调用解析时,调用函数c:

const b = () => Promise.resolve()
const a = () => {
    b().then(() => c())
}

当调用a时,将同步发生以下情况:

  • b被调用并返回一个Promise,该Promise将在将来某个时刻解决。
  • .then回调(实际上是调用c())被添加到回调链中( V8 术语中,[…]被添加为解析处理程序)。

之后,我们完成了在函数a的主体中执行代码。a永远不会被挂起,当对b的异步调用解析时,上下文已经消失了。

想象一下如果b(或c)异步抛出异常会发生什么?理想情况下,堆栈追踪应该包括a,因为b(或c)是从那里调用的,对吧?既然我们不在参考a了 ,那怎样能做到呢?

为了让它工作,JavaScript 引擎需要在上面的步骤之外做一些事情:它在有机会的时候捕获并存储堆栈追踪。

在V8中,堆栈追踪附加到b返回的Promise。当Promise实现时,堆栈追踪将被传递,以便c可以根据需要使用它。

b()[a] -> b().then()[a] -> c[a?:a]

捕获堆栈追踪需要时间(即降低性能);存储这些堆栈追踪需要内存。

async/await

下面是同样的程序,使用async/await而不是Promise编写:

const b = () => Promise.resolve()
const a = async () => {
  await b()
  c()
}

使用await,即使在await调用中不收集堆栈追踪,我们也可以恢复调用链。

这是可能的,因为a被挂起,正在等待b解决。如果b抛出异常,则可以按需以这种方式重建堆栈追踪。

如果c抛出异常,堆栈追踪可以像同步函数那样构造,因为发生这种情况时,我们仍在a上下文中。

通过遵循以下建议,使 JavaScript 引擎能够以更高效的方式处理堆栈追踪:

  • 偏好async/await胜过Promise。
  • 使用 @babel/preset env避免不必要的async/await传输。

以上就是JS异步堆栈追踪之为什么await胜过Promise的详细内容,更多关于Javascript的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
Jquery中删除元素的实现代码
Dec 29 Javascript
借助javascript代码判断网页是静态还是伪静态
May 05 Javascript
javaScript使用EL表达式的几种方式
May 27 Javascript
javascript多物体运动实现方法分析
Jan 08 Javascript
深入理解jQuery3.0的domManip函数
Sep 01 Javascript
基于JavaScript实现屏幕滚动效果
Jan 18 Javascript
Bootstrap datepicker日期选择器插件使用详解
Jul 26 Javascript
vue-cli与webpack处理静态资源的方法及webpack打包的坑
May 15 Javascript
微信小程序开发之map地图组件定位并手动修改位置偏差
Aug 17 Javascript
JS绘图Flot如何实现动态可刷新曲线图
Oct 16 Javascript
jquery实现加载更多"转圈圈"效果(示例代码)
Nov 09 jQuery
Vue的过滤器你真了解吗
Feb 24 Vue.js
vue引入Excel表格插件的方法
Apr 28 #Vue.js
react如何快速设置文件路径别名
原生JS封装vue Tab切换效果
vue项目两种方式实现竖向表格的思路分析
测量JavaScript函数的性能各种方式对比
Apr 27 #Javascript
比较node.js和Deno
Apr 27 #Javascript
如何用JavaScript检测当前浏览器是无头浏览器
Apr 27 #Javascript
You might like
php实现telnet功能示例
2014/04/08 PHP
PHP生成短网址的3种方法代码实例
2014/07/08 PHP
php集成环境xampp中apache无法启动问题解决方案
2014/11/18 PHP
thinkPHP中create方法与令牌验证实例浅析
2015/12/08 PHP
thinkPHP自动验证、自动添加及表单错误问题分析
2016/10/17 PHP
javascript Math.random()随机数函数
2009/11/04 Javascript
JS的replace方法详细介绍
2012/11/09 Javascript
js汉字转拼音实现代码
2013/02/06 Javascript
Web跨浏览器进程通信(Web跨域)
2013/04/17 Javascript
JS实现简单的tab切换选项卡效果
2016/09/21 Javascript
JS获取鼠标坐标并且根据鼠标位置不同弹出不同内容
2017/06/12 Javascript
Vue.js实现价格计算器功能
2020/03/30 Javascript
js 开发之autocomplete="off"在chrom中失效的解决办法
2017/09/28 Javascript
详解webpack 打包文件体积过大解决方案(code splitting)
2018/04/10 Javascript
Angular刷新当前页面的实现方法
2018/11/21 Javascript
浅谈Vue的响应式原理
2019/05/30 Javascript
解决layer 关闭当前弹窗 关闭遮罩层 input值获取不到的问题
2019/09/25 Javascript
vue+webpack 更换主题N种方案优劣分析
2019/10/28 Javascript
JavaScript基于用户照片姓名生成海报
2020/05/29 Javascript
Python实现端口复用实例代码
2014/07/03 Python
使用Python构建Hopfield网络的教程
2015/04/14 Python
python机器学习实战之最近邻kNN分类器
2017/12/20 Python
python中copy()与deepcopy()的区别小结
2018/08/03 Python
python列表推导式操作解析
2019/11/26 Python
python队列原理及实现方法示例
2019/11/27 Python
Python udp网络程序实现发送、接收数据功能示例
2019/12/09 Python
如何将tensorflow训练好的模型移植到Android (MNIST手写数字识别)
2020/04/22 Python
PyInstaller运行原理及常用操作详解
2020/06/13 Python
Python 如何调试程序崩溃错误
2020/08/03 Python
Python 爬虫批量爬取网页图片保存到本地的实现代码
2020/12/24 Python
全网最详细的PyCharm+Anaconda的安装过程图解
2021/01/25 Python
新加坡网上花店:FlowerAdvisor新加坡
2018/10/05 全球购物
相亲大会策划方案
2014/06/05 职场文书
四风问题对照检查材料思想汇报
2014/10/07 职场文书
三峡导游词
2015/01/31 职场文书
2015年副班长工作总结
2015/05/15 职场文书