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 相关文章推荐
iphone safari不支持position fixed的解决方法
May 04 Javascript
Extjs4 消息框去掉关闭按钮(类似Ext.Msg.alert)
Apr 02 Javascript
js异常捕获方法介绍
Apr 10 Javascript
javascript实现了照片拖拽点击置顶的照片墙代码
Apr 03 Javascript
详细解密jsonp跨域请求
Apr 15 Javascript
jQuery获取复选框被选中数量及判断选择值的方法详解
May 25 Javascript
在Web项目中引入Jquery插件报错的完美解决方案(图解)
Sep 19 Javascript
vue-scroller记录滚动位置的示例代码
Jan 17 Javascript
vue cli3.0结合echarts3.0与地图的使用方法示例
Mar 26 Javascript
微信小程序学习笔记之目录结构、基本配置图文详解
Mar 28 Javascript
教你完全理解ReentrantLock重入锁
Jun 03 Javascript
前端vue如何使用高德地图
Nov 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获取网络文件的实现代码
2010/01/01 PHP
PHP文件打开、关闭、写入的判断与执行代码
2011/05/24 PHP
浅谈ThinkPHP5.0版本和ThinkPHP3.2版本的区别
2017/06/17 PHP
php中加密解密DES类的简单使用方法示例
2020/03/26 PHP
关于PHP求解三数之和问题详析
2020/11/09 PHP
JS常用正则表达式总结
2013/11/12 Javascript
css配合jquery美化 select
2013/11/29 Javascript
模拟一个类似百度google的模糊搜索下拉列表
2014/04/15 Javascript
详解JavaScript的AngularJS框架中的表达式与指令
2016/03/05 Javascript
jquery实用技巧之输入框提示语句
2016/07/28 Javascript
JS异步加载的三种实现方式
2017/03/16 Javascript
Vue中父组件向子组件通信的方法
2017/07/11 Javascript
jQuery Form插件使用详解_动力节点Java学院整理
2017/07/17 jQuery
Vue组件实例间的直接访问实现代码
2017/08/20 Javascript
javascript实现电脑和手机版样式切换
2017/11/10 Javascript
详解webpack的proxyTable无效的解决方案
2018/06/15 Javascript
JavaScript函数式编程(Functional Programming)箭头函数(Arrow functions)用法分析
2019/05/22 Javascript
vue+eslint+vscode配置教程
2019/08/09 Javascript
小程序跨页面交互的作用与方法详解
2020/01/07 Javascript
vue自动添加浏览器兼容前后缀操作
2020/08/13 Javascript
Python使用ntplib库同步校准当地时间的方法
2016/07/02 Python
使用python在本地电脑上快速处理数据
2017/06/22 Python
python的re正则表达式实例代码
2018/01/24 Python
python GUI库图形界面开发之PyQt5布局控件QGridLayout详细使用方法与实例
2020/03/06 Python
科颜氏法国官网:Kiehl’s法国
2019/08/20 全球购物
西班牙品牌鞋子、服装和配饰在线商店:Esdemarca
2021/02/17 全球购物
什么是方法的重载
2013/06/24 面试题
养殖人员的创业计划书范文
2013/12/26 职场文书
我的五年职业生涯规划
2014/01/23 职场文书
市场营销专业求职信
2014/06/17 职场文书
优秀党员学习焦裕禄精神思想汇报范文
2014/09/10 职场文书
2014年终工作总结范本
2014/12/15 职场文书
八一建军节慰问信
2015/02/14 职场文书
2015年派出所民警工作总结
2015/04/24 职场文书
高中信息技术教学反思
2016/02/16 职场文书
漫画「处刑少女的生存之道」第3卷封面公开
2022/03/21 日漫