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 相关文章推荐
『jQuery』.html(),.text()和.val()的概述及使用
Apr 22 Javascript
js仿百度有啊通栏展示效果实现代码
May 28 Javascript
node.js中的fs.fchown方法使用说明
Dec 16 Javascript
jQuery实现“扫码阅读”功能
Jan 21 Javascript
JQuery CheckBox(复选框)操作方法汇总
Apr 15 Javascript
JS控制TreeView的结点选择
Nov 11 Javascript
ionic2 tabs使用 Modal底部tab弹出框
Dec 30 Javascript
基于匀速运动的实例讲解(侧边栏,淡入淡出)
Oct 17 Javascript
vue2.0在table中实现全选和反选的示例代码
Nov 04 Javascript
JavaScript 中定义函数用 var foo = function () {} 和 function foo()区别介绍
Mar 01 Javascript
Hexo已经看腻了,来手把手教你使用VuePress搭建个人博客
Apr 26 Javascript
微信小程序实现城市列表选择
Jun 05 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 smarty模版引擎中变量操作符及使用方法
2009/12/11 PHP
PHP操作Memcache实例介绍
2013/06/14 PHP
解析file_get_contents模仿浏览器头(user_agent)获取数据
2013/06/27 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
2017/09/29 PHP
Docker 安装 PHP并与Nginx的部署实例讲解
2021/02/27 PHP
基于jquery实现发送文章到手机的代码
2014/12/26 Javascript
jquery点击改变class并toggle的实现代码
2016/05/15 Javascript
用Vue.js实现监听属性的变化
2016/11/17 Javascript
JS键盘版计算器的制作方法
2016/12/03 Javascript
vue router demo详解
2017/10/13 Javascript
详解小程序如何改变onLoad的执行时机
2019/11/01 Javascript
vue组件库的在线主题编辑器的实现思路
2020/04/03 Javascript
JS正则表达式常见函数与用法小结
2020/04/13 Javascript
JavaScript ECMA-262-3 深入解析(一):执行上下文实例分析
2020/04/25 Javascript
单线程JavaScript实现异步过程详解
2020/05/19 Javascript
JavaScript数组常用的增删改查与其他属性详解
2020/10/13 Javascript
[01:20:30]OG vs LGD 2018国际邀请赛淘汰赛BO3 第四场 8.26
2018/08/30 DOTA
Python计算程序运行时间的方法
2014/12/13 Python
用Python操作字符串之rindex()方法的使用
2015/05/19 Python
pandas删除指定行详解
2019/04/04 Python
Pycharm新手教程(只需要看这篇就够了)
2019/06/18 Python
Python3+PyInstall+Sciter解决报错缺少dll、html等文件问题
2019/07/15 Python
python中seaborn包常用图形使用详解
2019/11/25 Python
Python几种常见算法汇总
2020/06/02 Python
基于python实现图片转字符画代码实例
2020/09/04 Python
编写类String 的构造函数、析构函数和赋值函数
2012/09/09 面试题
大学生求职计划书
2014/04/30 职场文书
奥林匹克运动会口号
2014/06/19 职场文书
我的中国梦演讲稿小学篇
2014/08/19 职场文书
个人自我剖析材料
2014/09/30 职场文书
2014年审计工作总结
2014/11/17 职场文书
工作失误检讨书范文
2015/01/26 职场文书
公司文体活动总结
2015/05/07 职场文书
使用qt quick-ListView仿微信好友列表和聊天列表的示例代码
2021/06/13 Python
bat批处理之字符串操作的实现
2022/03/16 Python
CentOS7 minimal 最小化安装网络设置过程
2022/12/24 Servers