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 参数中的数组展开 [译]
Sep 21 Javascript
jquery创建表格(自动增加表格)代码分享
Dec 25 Javascript
一个非常全面的javascript URL解析函数和分段URL解析方法
Apr 12 Javascript
javascript时间函数大全
Jun 30 Javascript
js在IE与firefox的差异集锦
Nov 11 Javascript
jQuery源码分析之Callbacks详解
Mar 13 Javascript
基于JavaScript创建动态Dom
Dec 08 Javascript
Js遍历键值对形式对象或Map形式的方法
Aug 08 Javascript
Angular多选、全选、批量选择操作实例代码
Mar 10 Javascript
vue.js 上传图片实例代码
Jun 22 Javascript
JavaScript实现构造json数组的方法分析
Aug 17 Javascript
微信内置浏览器图片查看器的代码实例
Oct 08 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字符串的连接的简单实例
2013/12/30 PHP
PHP定时更新程序设计思路分享
2014/06/10 PHP
laravel model 两表联查示例
2019/10/24 PHP
laravel通用化的CURD的实现
2019/12/13 PHP
jQuery 源码分析笔记(7) Queue
2011/06/19 Javascript
jQuery事件 delegate()使用方法介绍
2012/10/30 Javascript
jQuery 文本框得失焦点的简单实例
2014/02/19 Javascript
nodejs分页类代码分享
2014/06/17 NodeJs
详解JavaScript函数
2015/12/01 Javascript
JavaScript时间操作之年月日星期级联操作
2016/01/15 Javascript
js数组的五种迭代方法及两种归并方法(推荐)
2016/06/14 Javascript
javascript弹出窗口中增加确定取消按钮
2016/06/24 Javascript
javascript 取小数点后几位几种方法总结
2017/08/02 Javascript
基于JavaScript中标识符的命名规则介绍
2018/01/06 Javascript
深入浅析Vue.js 中的 v-for 列表渲染指令
2018/11/19 Javascript
JavaScript检测浏览器是否支持CSS变量代码实例
2020/04/03 Javascript
js将日期格式转换为YYYY-MM-DD HH:MM:SS
2020/09/18 Javascript
在vue项目中 实现定义全局变量 全局函数操作
2020/10/26 Javascript
Python Deque 模块使用详解
2014/07/04 Python
浅谈Python的Django框架中的缓存控制
2015/07/24 Python
python3读取csv和xlsx文件的实例
2018/06/22 Python
总结python中pass的作用
2019/02/27 Python
python使用多线程编写tcp客户端程序
2019/09/02 Python
keras 使用Lambda 快速新建层 添加多个参数操作
2020/06/10 Python
Born鞋子官网:Born Shoes
2017/04/06 全球购物
屈臣氏官方旗舰店:亚洲享负盛名的保健及美妆零售商
2019/03/15 全球购物
关爱老人标语
2014/06/21 职场文书
学校安全生产月活动总结
2014/07/05 职场文书
党委干部批评与自我批评发言稿
2014/09/28 职场文书
班主任工作实习计划
2015/01/16 职场文书
个人股份转让协议书范本
2015/01/28 职场文书
综合办公室岗位职责
2015/04/11 职场文书
银行求职信范文
2019/05/13 职场文书
创业计划书之健康营养产业
2019/10/15 职场文书
Python实战之OpenCV实现猫脸检测
2021/06/26 Python
MySQL数据库表约束讲解
2022/06/21 MySQL