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创建数据共享接口——简化框架之间相互传值
Oct 23 Javascript
JavaScript高级程序设计 阅读笔记(十二) js内置对象Math
Aug 14 Javascript
php+js实现倒计时功能
Jun 02 Javascript
JavaScript设计模式之装饰者模式介绍
Dec 28 Javascript
JavaScript DOM事件(笔记)
Apr 08 Javascript
纯javascript模仿微信打飞机小游戏
Aug 20 Javascript
JavaScript获取服务器端时间的方法
Nov 29 Javascript
react.js组件实现拖拽复制和可排序的示例代码
Aug 20 Javascript
如何为vuex实现带参数的 getter和state.commit
Jan 04 Javascript
微信提示 在浏览器打开 效果实现过程解析
Sep 10 Javascript
mpvue网易云短信接口实现小程序短信登录的示例代码
Apr 03 Javascript
vue elementui tree 任意级别拖拽功能代码
Aug 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
建立动态的WML站点(一)
2006/10/09 PHP
php select,radio和checkbox默认选择的实现方法
2010/05/15 PHP
APACHE的AcceptPathInfo指令使用介绍
2013/01/18 PHP
PHP中date与gmdate的区别及默认时区设置
2014/05/12 PHP
php+laravel依赖注入知识点总结
2019/11/04 PHP
用jQuery toggleClass 实现鼠标移上变色
2014/05/14 Javascript
JS模态窗口返回值兼容问题的完美解决方法
2016/05/28 Javascript
js本地图片预览实现代码
2016/10/09 Javascript
如何将 jQuery 从你的 Bootstrap 项目中移除(取而代之使用Vue.js)
2017/07/17 jQuery
js实现移动端tab切换时下划线滑动效果
2019/09/08 Javascript
layer关闭当前窗口页面以及确认取消按钮的方法
2019/09/09 Javascript
Vue.js数字输入框组件使用方法详解
2019/10/19 Javascript
关于vue的列表图片选中打钩操作
2020/09/09 Javascript
python实现多线程抓取知乎用户
2016/12/12 Python
使用Python对Access读写操作
2017/03/30 Python
详解python中的 is 操作符
2017/12/26 Python
一文带你了解Python中的字符串是什么
2018/11/20 Python
python中可以声明变量类型吗
2020/06/18 Python
浅谈pytorch中的BN层的注意事项
2020/06/23 Python
浅谈Python描述数据结构之KMP篇
2020/09/06 Python
浅析HTML5中的download属性使用
2019/03/13 HTML / CSS
苹果香港官方商城:Apple香港
2016/09/14 全球购物
草莓网化妆品澳大利亚站:Strawberrynet AU
2017/12/18 全球购物
经管应届生求职信
2013/11/17 职场文书
会计电算化专业毕业生求职信范文
2013/12/10 职场文书
2014年会演讲稿范文
2014/01/06 职场文书
表彰先进集体通报
2014/01/12 职场文书
无故旷工检讨书
2014/01/26 职场文书
《值日生》教学反思
2014/02/17 职场文书
临床医师个人自我评价
2014/04/06 职场文书
学生安全责任书
2014/04/15 职场文书
三好学生演讲稿范文
2014/04/26 职场文书
毕业评语大全
2014/05/04 职场文书
人口与计划生育目标管理责任书
2014/07/29 职场文书
2014年办公室个人工作总结
2014/11/12 职场文书
给朋友的道歉短信
2015/05/12 职场文书