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 相关文章推荐
图片无缝滚动代码(向左/向下/向上)
Apr 10 Javascript
jQuery动态修改超链接地址的方法
Feb 13 Javascript
javascript jquery对form元素的常见操作详解
Jun 12 Javascript
jQuery实现页面点击后退弹出提示框的方法
Aug 24 Javascript
webpack-dev-server自动更新页面方法
Feb 22 Javascript
微信小程序实现富文本图片宽度自适应的方法
Jan 20 Javascript
vue中使用[provide/inject]实现页面reload的方法
Sep 30 Javascript
在VUE中实现文件下载并判断状态的方法
Nov 08 Javascript
小程序如何写动态标签的实现方法
Feb 05 Javascript
Vue将props值实时传递 并可修改的操作
Aug 09 Javascript
ztree+ajax实现文件树下载功能
May 18 Javascript
Vue CLI中模式与环境变量的深入详解
May 30 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 向右侧拉菜单实现代码,测试使用中
2009/11/03 PHP
深入解析yii权限分级式访问控制的实现(非RBAC法)
2013/06/13 PHP
php构造函数实例讲解
2013/11/13 PHP
PHP将进程作为守护进程的方法
2015/03/19 PHP
护卫神php套件 php版本升级方法(php5.5.24)
2015/05/10 PHP
PHP面向对象之工作单元(实例讲解)
2017/06/26 PHP
PHP实现对图片的反色处理功能【测试可用】
2018/02/01 PHP
php如何把表单内容提交到数据库
2019/07/08 PHP
gearman中worker常驻后台,导致MySQL server has gone away的解决方法
2020/02/27 PHP
用javascript获取地址栏参数
2006/12/22 Javascript
菜鸟javascript基础整理1
2010/12/06 Javascript
javascript继承之为什么要继承
2012/11/10 Javascript
利用JS解决ie6不支持max-width,max-height问题的方法
2014/01/02 Javascript
利用jquery动画特效和css打造的侧边弹出垂直导航
2014/04/04 Javascript
jQuery中filter()方法用法实例
2015/01/06 Javascript
js选择器全面解析
2016/06/27 Javascript
深入理解选择框脚本[推荐]
2016/12/13 Javascript
bootstrap 模态框(modal)实现水平垂直居中显示
2017/01/23 Javascript
a标签置灰不可点击的实现方法
2017/02/06 Javascript
js每隔两秒输出数组中的一项(实例)
2017/05/28 Javascript
基于Koa2写个脚手架模拟接口服务的方法
2018/11/27 Javascript
写一个Vue Popup组件
2019/02/25 Javascript
详解ES6 export default 和 import语句中的解构赋值
2019/05/28 Javascript
vue element 生成无线级左侧菜单的实现代码
2019/08/21 Javascript
Vue CLI项目 axios模块前后端交互的使用(类似ajax提交)
2019/09/01 Javascript
js 递归json树实现根据子id查父id的方法分析
2019/11/08 Javascript
Python文件操作,open读写文件,追加文本内容实例
2016/12/14 Python
完美解决Django2.0中models下的ForeignKey()问题
2020/05/19 Python
详解CSS3:overflow属性
2020/11/17 HTML / CSS
eBay荷兰购物网站:eBay.nl
2020/06/26 全球购物
常务副总经理岗位职责
2014/04/12 职场文书
幼儿教师师德演讲稿
2014/05/06 职场文书
车辆年审委托书范本
2014/09/18 职场文书
获奖感言范文
2015/07/31 职场文书
MySQL kill不掉线程的原因
2021/05/07 MySQL
HttpClient实现文件上传功能
2022/08/14 Java/Android