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的动态表格插件
Mar 28 Javascript
iframe 异步加载技术及性能分析
Jul 19 Javascript
jQuery遍历Form示例代码
Sep 03 Javascript
浅析JavaScript中两种类型的全局对象/函数
Dec 05 Javascript
推荐9款炫酷的基于jquery的页面特效
Dec 07 Javascript
简述JavaScript提交表单的方式 (Using JavaScript Submit Form)
Mar 18 Javascript
简介BootStrap model弹出框的使用
Apr 27 Javascript
原生js 封装get ,post, delete 请求的实例
Aug 11 Javascript
详解node登录接口之密码错误限制次数(含代码)
Oct 25 Javascript
Servlet返回的数据js解析2种方法
Dec 12 Javascript
js实现div色块碰撞
Jan 16 Javascript
jQuery 判断元素是否存在然后按需加载内容的实现代码
Jan 16 jQuery
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
用PHPdig打造属于你自己的Google[图文教程]
2007/02/14 PHP
php中计算未知长度的字符串哪个字符出现的次数最多的代码
2012/08/14 PHP
PHP 返回13位时间戳的实现代码
2016/05/13 PHP
javascript indexOf函数使用说明
2008/07/03 Javascript
js自定义事件代码说明
2011/01/31 Javascript
javascript 运算数的求值顺序
2011/08/23 Javascript
解析Jquery取得iframe中元素的几种方法
2013/07/04 Javascript
利用毫秒减值计算时长的js代码
2013/09/22 Javascript
做好七件事帮你提升jQuery的性能
2014/02/06 Javascript
Visual Studio中js调试的方法图解
2014/06/30 Javascript
推荐25个超炫的jQuery网格插件
2014/11/28 Javascript
JavaScript中Boolean对象的属性解析
2015/10/21 Javascript
jQuery实现的仿百度分页足迹效果代码
2015/10/30 Javascript
详解JavaScript的流程控制语句
2015/11/30 Javascript
jQuery 中的 DOM 操作
2016/04/26 Javascript
简单实现js无缝滚动效果
2017/02/05 Javascript
基于vue-ssr服务端渲染入门详解
2018/01/08 Javascript
微信小程序实现tab页面切换功能
2018/07/13 Javascript
nodejs 生成和导出 word的实例代码
2018/07/31 NodeJs
浅谈从React渲染流程分析Diff算法
2018/09/08 Javascript
angularJS1 url中携带参数的获取方法
2018/10/09 Javascript
JavaScript创建防篡改对象的方法分析
2018/12/30 Javascript
angular 实现下拉列表组件的示例代码
2019/03/09 Javascript
webpack项目使用eslint建立代码规范实现
2019/05/16 Javascript
Python的Bottle框架的一些使用技巧介绍
2015/04/08 Python
使用Python的urllib2模块处理url和图片的技巧两则
2016/02/18 Python
Python数据结构与算法之图的广度优先与深度优先搜索算法示例
2017/12/14 Python
python中的tcp示例详解
2018/12/09 Python
python中时间、日期、时间戳的转换的实现方法
2019/07/06 Python
使用TensorFlow-Slim进行图像分类的实现
2019/12/31 Python
纽约著名的服装辅料来源:M&J Trimming
2017/07/26 全球购物
泰国最新活动和优惠:Megatix
2020/05/07 全球购物
仲裁协议书
2014/09/26 职场文书
监理中标通知书
2015/04/16 职场文书
消防宣传语大全
2015/07/13 职场文书
python编程项目中线上问题排查与解决
2021/11/01 Python