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 相关文章推荐
Some tips of wmi scripting in jscript (1)
Apr 03 Javascript
Web开发者必备的12款超赞jQuery插件
Dec 03 Javascript
用jQuery与JSONP轻松解决跨域访问的问题
Feb 04 Javascript
Javascript基于对象三大特性(封装性、继承性、多态性)
Jan 04 Javascript
jquery插件Jplayer使用方法简析
Apr 22 Javascript
AngularJs解决跨域问题案例详解(简单方法)
May 19 Javascript
jquery attr()设置和获取属性值实例教程
Sep 25 Javascript
React Native中Mobx的使用方法详解
Dec 04 Javascript
基于JavaScript 实现拖放功能
Sep 12 Javascript
在vue中实现禁止屏幕滚动,禁止屏幕滑动
Jul 22 Javascript
vue根据条件不同显示不同按钮的操作
Aug 04 Javascript
详解如何在Canvas中添加事件的方法
Apr 17 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
教你如何把一篇文章按要求分段
2006/10/09 PHP
php 仿Comsenz安装效果代码打包提供下载
2010/05/09 PHP
《PHP编程最快明白》第三讲:php数组
2010/11/01 PHP
PHP+Mysql+jQuery文件下载次数统计实例讲解
2015/10/10 PHP
Yii2 rbac权限控制之rule教程详解
2016/06/23 PHP
javascript利用apply和arguments复用方法
2013/11/25 Javascript
javascript基于DOM实现权限选择实例分析
2015/05/14 Javascript
JS实现适合于后台使用的动画折叠菜单效果
2015/09/21 Javascript
jQuery页面加载初始化的3种方法(推荐)
2016/06/02 Javascript
Bootstrap学习系列之使用 Bootstrap Typeahead 组件实现百度下拉效果
2016/07/07 Javascript
js 中获取制定的cook信息实现方法
2016/11/19 Javascript
mpvue将vue项目转换为小程序
2018/09/30 Javascript
动态内存分配导致影响Javascript性能的问题
2018/12/18 Javascript
JavaScript中常用的简洁高级技巧总结
2019/03/10 Javascript
vue+swiper实现左右滑动的测试题功能
2020/10/30 Javascript
对vue生命周期的深入理解
2020/12/03 Vue.js
Vue在H5 项目中使用融云进行实时个人单聊通讯
2020/12/14 Vue.js
python实现端口转发器的方法
2015/03/13 Python
Python 判断 有向图 是否有环的实例讲解
2018/02/01 Python
Python中生成器和迭代器的区别详解
2018/02/10 Python
pandas 透视表中文字段排序方法
2018/11/16 Python
pycharm运行和调试不显示结果的解决方法
2018/11/30 Python
python for和else语句趣谈
2019/07/02 Python
Django 反向生成url实例详解
2019/07/30 Python
Django的CVB实例详解
2020/02/10 Python
opencv+python实现均值滤波
2020/02/19 Python
TensorFlow-gpu和opencv安装详细教程
2020/06/30 Python
大学生见习报告总结
2014/11/04 职场文书
2014年村委会工作总结
2014/11/24 职场文书
2014年环境整治工作总结
2014/12/10 职场文书
保证金退回承诺函格式
2015/01/21 职场文书
高三英语教学计划
2015/01/23 职场文书
辞职信的写法
2015/02/27 职场文书
学习型家庭事迹材料(2016精选版)
2016/02/29 职场文书
Redis分布式锁Redlock的实现
2021/08/07 Redis
深入理解pytorch库的dockerfile
2022/06/10 Python