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 相关文章推荐
IE JS无提示关闭窗口不提示的方法
Apr 29 Javascript
从零开始学习jQuery (六) jquery中的AJAX使用
Feb 23 Javascript
JavaScript常用脚本汇总(三)
Mar 04 Javascript
jQuery标签编辑插件Tagit使用指南
Apr 21 Javascript
js中setTimeout()与clearTimeout()用法实例浅析
May 12 Javascript
Jquery常用的方法汇总
Sep 01 Javascript
每天一篇javascript学习小结(String对象)
Nov 18 Javascript
极力推荐10个短小实用的JavaScript代码段
Aug 03 Javascript
微信小程序之小豆瓣图书实例
Nov 30 Javascript
详解JavaScript树结构
Jan 09 Javascript
基于AngularJS的简单使用详解
Sep 10 Javascript
基于element-ui封装表单金额输入框的方法示例
Jan 06 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一行代码获取文件后缀名实例分析
2014/11/12 PHP
PDO::exec讲解
2019/01/28 PHP
15个款优秀的 jQuery 图片特效插件推荐
2011/11/21 Javascript
javascript:history.go()和History.back()的区别及应用
2012/11/25 Javascript
jQuery extend 的简单实例
2013/09/18 Javascript
jquery 页面滚动到底部自动加载插件集合
2014/01/31 Javascript
基于Node.js实现nodemailer邮件发送
2016/01/26 Javascript
JavaScript实现弹出模态窗体并接受传值的方法
2016/02/12 Javascript
JavaScript数组去重的两种方法推荐
2016/04/05 Javascript
CentOS 安装NodeJS V8.0.0的方法
2017/06/15 NodeJs
深入理解vue Render函数
2017/07/19 Javascript
AngularJS实现的锚点楼层跳转功能示例
2018/01/02 Javascript
js根据json数据中的某一个属性来给数据分组的方法
2018/10/08 Javascript
微信小程序云开发之使用云数据库
2019/05/17 Javascript
一文快速了解JQuery中的AJAX
2019/05/31 jQuery
解决echarts echarts数据动态更新和dataZoom被重置问题
2020/07/20 Javascript
从零学python系列之浅谈pickle模块封装和拆封数据对象的方法
2014/05/23 Python
深入理解python中的select模块
2017/04/23 Python
Python实现解析Bit Torrent种子文件内容的方法
2017/08/29 Python
python中numpy.zeros(np.zeros)的使用方法
2017/11/07 Python
PyQt5每天必学之拖放事件
2020/08/27 Python
Python在图片中插入大量文字并且自动换行
2019/01/02 Python
pyinstaller参数介绍以及总结详解
2019/07/12 Python
解决Numpy中sum函数求和结果维度的问题
2019/12/06 Python
你所知道的集合类都有哪些?主要方法?
2012/12/31 面试题
在校学生职业规划范文
2014/01/08 职场文书
管理学院毕业生自荐信范文
2014/03/10 职场文书
小学生综合素质评语
2014/04/23 职场文书
国庆节演讲稿
2014/05/27 职场文书
大学生国庆节65周年演讲稿范文
2014/09/25 职场文书
2014年实习期工作总结
2014/11/27 职场文书
2014年心理健康教育工作总结
2014/12/06 职场文书
2014年幼儿园班级工作总结
2014/12/17 职场文书
2016消防宣传标语口号
2015/12/26 职场文书
微信小程序实现轮播图指示器
2022/06/25 Javascript
Mysql的Table doesn't exist问题及解决
2022/12/24 MySQL