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 相关文章推荐
用Javascript评估用户输入密码的强度(Knockout版)
Nov 30 Javascript
jQuery性能优化28条建议你值得借鉴
Feb 16 Javascript
ExtJS中设置下拉列表框不可编辑的方法
May 07 Javascript
JavaScript控制按钮可用或不可用的方法
Apr 03 Javascript
javascript实现图片自动和可控的轮播切换特效
Apr 13 Javascript
浅谈关于JavaScript API设计的一些建议和准则
Jun 24 Javascript
Javascript中的作用域和上下文深入理解
Jul 03 Javascript
Webpack性能优化 DLL 用法详解
Aug 10 Javascript
vue.js select下拉框绑定和取值方法
Mar 03 Javascript
原生JS实现的雪花飘落动画效果
May 03 Javascript
说说如何在Vue.js中实现数字输入组件的方法
Jan 08 Javascript
利用JavaScript模拟京东按键输入功能
Dec 01 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
PHP5中使用PDO连接数据库的方法
2010/08/01 PHP
php中关于codeigniter的xmlrpc的类在进行数据交换时的类型问题
2011/07/03 PHP
Zend Framework教程之Application和Bootstrap用法详解
2016/03/10 PHP
php+ajax实现商品对比功能示例
2019/04/13 PHP
ThinkPHP 框架实现的读取excel导入数据库操作示例
2020/04/14 PHP
js直接编辑当前cookie的脚本
2008/09/14 Javascript
用js判断页面是否加载完成实现代码
2012/12/11 Javascript
jquery获取自定义属性(attr和prop)实例介绍
2013/04/21 Javascript
通过AJAX的JS、JQuery两种方式解析XML示例介绍
2013/09/23 Javascript
在页面中js获取光标/鼠标的坐标及光标的像素坐标
2013/11/11 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
2015/08/04 Javascript
Sort()函数的多种用法
2016/03/20 Javascript
原生JS版和jquery版实现checkbox的全选/全不选/点选/行内点选(Mr.Think)
2016/10/29 Javascript
JavaScript实现简单评论功能
2017/08/17 Javascript
JavaScript实现简单图片轮播效果
2017/08/21 Javascript
详解webpack编译多页面vue项目的配置问题
2017/12/11 Javascript
select标签设置默认选中的选项方法
2018/03/02 Javascript
一文了解Vue中的nextTick
2019/05/06 Javascript
JS实现给数组对象排序的方法分析
2019/06/24 Javascript
python文件名和文件路径操作实例
2017/09/29 Python
Pycharm 创建 Django admin 用户名和密码的实例
2018/05/30 Python
Python自定义装饰器原理与用法实例分析
2018/07/16 Python
python+opencv边缘提取与各函数参数解析
2020/03/09 Python
python3.6.8 + pycharm + PyQt5 环境搭建的图文教程
2020/06/11 Python
Pytorch如何切换 cpu和gpu的使用详解
2021/03/01 Python
Canvas globalCompositeOperation
2018/12/18 HTML / CSS
香港优质食材和美酒专门店:FoodWise
2017/09/01 全球购物
CLR与IL分别是什么含义
2016/08/23 面试题
圣诞节红领巾广播稿
2014/02/03 职场文书
学生个人自我鉴定
2014/03/26 职场文书
社区两委对照检查材料
2014/08/23 职场文书
医德医风个人工作总结2014
2014/11/14 职场文书
2015年暑期社会实践活动总结
2015/03/27 职场文书
文化大革命观后感
2015/06/17 职场文书
解决SpringBoot跨域的三种方式
2021/06/26 Java/Android
电脑开机弹出documents文件夹怎么回事?弹出documents文件夹解决方法
2022/04/08 数码科技