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 图片缩放效果代码
Jun 09 Javascript
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
May 23 Javascript
Jquery的Tabs内容轮换效果实现代码,几行搞定
Feb 12 Javascript
JavaScript控制table某列不显示的方法
Mar 16 Javascript
浅析JS动态创建元素【两种方法】
Apr 20 Javascript
拥Bootstrap入怀——导航栏篇
May 30 Javascript
jQuery实现倒计时(倒计时年月日可自己输入)
Dec 02 Javascript
Angular 4.x+Ionic3踩坑之Ionic 3.x界面传值详解
Mar 13 Javascript
jquery 键盘事件 keypress() keydown() keyup()用法总结
Oct 23 jQuery
JS三级联动代码格式实例详解
Dec 30 Javascript
JS实现购物车基本功能
Nov 08 Javascript
Vue 防止短时间内连续点击后多次触发请求的操作
Nov 11 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生成随机数或者字符串的代码
2008/09/05 PHP
PHP下使用mysqli的函数连接mysql出现warning: mysqli::real_connect(): (hy000/1040): ...
2016/02/14 PHP
PHP自动补全表单的两种方法
2017/03/06 PHP
PHP利用二叉堆实现TopK-算法的方法详解
2017/04/24 PHP
Laravel 使用查询构造器配合原生sql语句查询的例子
2019/10/12 PHP
ASP.NET jQuery 实例13 原创jQuery文本框字符限制插件-TextArea Counter
2012/02/03 Javascript
javascript中自定义对象的属性方法分享
2013/07/12 Javascript
Firefox中通过JavaScript复制数据到剪贴板(Copy to Clipboard 跨浏览器版)
2013/11/22 Javascript
For循环中分号隔开的3部分的执行顺序探讨
2014/05/27 Javascript
生成二维码方法汇总
2014/12/26 Javascript
JavaScript设计模式之装饰者模式介绍
2014/12/28 Javascript
requireJS使用指南
2016/04/27 Javascript
jquery实现限制textarea输入字数的方法
2017/09/06 jQuery
JavaScript动态创建二维数组的方法示例
2019/02/01 Javascript
es6中class类静态方法,静态属性,实例属性,实例方法的理解与应用分析
2020/02/15 Javascript
NodeJS多种创建WebSocket监听的方式(三种)
2020/06/04 NodeJs
[43:47]DOTA2上海特级锦标赛主赛事日 - 4 败者组第四轮#2 MVP.Phx VS Fnatic第一局
2016/03/05 DOTA
pymssql ntext字段调用问题解决方法
2008/12/17 Python
零基础写python爬虫之神器正则表达式
2014/11/06 Python
详解Python Socket网络编程
2016/01/05 Python
Python编程实现生成特定范围内不重复多个随机数的2种方法
2017/04/14 Python
python使用锁访问共享变量实例解析
2018/02/08 Python
在mac下查找python包存放路径site-packages的实现方法
2018/11/06 Python
Python操作远程服务器 paramiko模块详细介绍
2019/08/07 Python
python hashlib加密实现代码
2019/10/17 Python
Django contrib auth authenticate函数源码解析
2020/11/12 Python
出门问问全球官方商城:Tichome音箱和TicWatch智能手表
2017/12/02 全球购物
解释i节点在文件系统中的作用
2013/11/26 面试题
应届生护士求职信
2013/11/01 职场文书
大学生第一学年自我鉴定2015
2014/09/28 职场文书
个人年终总结范文
2015/03/09 职场文书
婚育证明样本
2015/06/16 职场文书
PyQt5结合QtDesigner实现文本框读写操作
2021/06/11 Python
python装饰器代码解析
2022/03/23 Python
苹果发布了MagSafe固件更新,可以不外接电源实现最高7.5W充电
2022/04/21 数码科技
springboot为异步任务规划自定义线程池的实现
2022/06/14 Java/Android