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 相关文章推荐
电子商务网站上的常用的js放大镜效果
Dec 08 Javascript
页面加载完毕后滚动条自动滚动一定位置
Feb 20 Javascript
node.js中的path.normalize方法使用说明
Dec 08 Javascript
超级简单实现JavaScript MVC 样式框架
Mar 24 Javascript
JavaScript调用客户端Java程序的方法
Jul 27 Javascript
Node.js Addons翻译(C/C++扩展)
Jun 12 Javascript
基于JS如何实现给字符加千分符(65,541,694,158)
Aug 03 Javascript
JavaScript递归算法生成树形菜单
Aug 15 Javascript
详解基于DllPlugin和DllReferencePlugin的webpack构建优化
Jun 28 Javascript
详解vue.js下引入百度地图jsApi的两种方法
Jul 27 Javascript
Vue 表情包输入组件的实现代码
Jan 21 Javascript
利用 JavaScript 实现并发控制的示例代码
Dec 31 Javascript
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中source #N问题的解决方法
2014/01/27 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
2015/04/08 PHP
你不知道的文件上传漏洞php代码分析
2016/09/29 PHP
PHP 芝麻信用接入的注意事项
2016/12/01 PHP
JS类定义原型方法的两种实现的区别评论很多
2007/09/12 Javascript
JavaScript学习点滴 call、apply的区别
2010/10/22 Javascript
jquery修改属性值实例代码(设置属性值)
2014/01/06 Javascript
对 jQuery 中 data 方法的误解分析
2014/06/18 Javascript
Labelauty?jQuery单选框/复选框美化插件分享
2015/09/26 Javascript
jQuery实现按钮点击遮罩加载及处理完后恢复的效果
2016/06/07 Javascript
Bootstrap复选框和单选按钮美化插件(推荐)
2016/11/23 Javascript
原生Javascript插件开发实践
2017/01/09 Javascript
jQuery插件HighCharts绘制2D圆环图效果示例【附demo源码下载】
2017/03/09 Javascript
JavaScript仿微信(电话)联系人列表滑动字母索引实例讲解(推荐)
2017/08/16 Javascript
vue检测对象和数组的变化分析
2018/06/30 Javascript
JavaScript实现轮播图特效
2020/04/10 Javascript
vue 子组件修改data或调用操作
2020/08/07 Javascript
详解Java中String JSONObject JSONArray List转换
2020/11/13 Javascript
在Windows系统上搭建Nginx+Python+MySQL环境的教程
2015/12/25 Python
Flask框架Flask-Login用法分析
2018/07/23 Python
python3 json数据格式的转换(dumps/loads的使用、dict to str/str to dict、json字符串/字典的相互转换)
2019/04/01 Python
在python plt图表中文字大小调节的方法
2019/07/08 Python
python+pygame实现坦克大战
2019/09/10 Python
matlab灰度图像调整及imadjust函数的用法详解
2020/02/27 Python
Python任务调度利器之APScheduler详解
2020/04/02 Python
python学生管理系统的实现
2020/04/05 Python
Django def clean()函数对表单中的数据进行验证操作
2020/07/09 Python
python 常见的反爬虫策略
2020/09/27 Python
联想澳大利亚官网:Lenovo Australia
2018/01/18 全球购物
添柏岚英国官方网站:Timberland英国
2019/11/28 全球购物
会展策划与管理专业大学生职业生涯规划
2014/02/07 职场文书
项目经理任命书
2014/06/04 职场文书
反腐倡廉剖析材料
2014/09/30 职场文书
教师评职称工作总结2015
2015/04/20 职场文书
老乡聚会通知
2015/04/23 职场文书
民政局2016年“六一”儿童节慰问活动总结
2016/04/06 职场文书