JavaScript如何在后期的.catch处理程序中捕获异常?

问题描述

前几天,我遇到了以下和平代码:

let promise = Promise.reject(new Error('Promise Failed!')); // 1

setTimeout(() => promise.catch(err => alert('caught')),1000); // 2

// 3

所以我很惊讶地发现错误是在错误发生一秒钟后被注册的处理程序中捕获的。

现在,让我逐步说明我的理解方式,以便您可以纠正我并告诉我哪里错了:

  1. 在执行整个脚本的当前宏任务期间,promise会拒绝(1),并且由于没有注册的拒绝处理程序,因此控件会依次移至下一行。
  2. 我们调用setTimeout传递给它一个回调函数,其中要注册拒绝处理程序(2)。但是,仅在第二次延迟后才安排此回调。此外,它将在单独任务中执行。
  3. 执行在第 3 行上。 当前宏任务已完成,堆栈和任务队列均为空。剩下的就是等待给定的1秒延迟。
  4. 一秒超时已完成。我们的回调到达任务队列,并立即被推送到有效运行它的堆栈。
  5. 在执行回调函数(这是 new 任务的一部分)期间,.catch处理程序已注册为一秒钟前被拒绝的承诺,该承诺发生在上一个并且已经完成的任务。但是,它成功地捕获了错误。

这是否意味着一直以来该错误一直在内存中的某个地方,等待.catch处理程序稍后可能被注册?但是,如果从未发生过并且被拒绝的承诺数量增加了怎么办?是否会在内存中保留未处理的错误以使其“挂起”,等待其处理程序被注册?

解决方法

这是否意味着一直以来该错误一直在内存中的某个地方等待着可能稍后再注册.catch处理程序?

是的,它存储在promise对象中。注意,promise是not just a notification mechanism,它们用于表示一次性异步任务的 result 。履行时,履行价值或拒绝原因(在您的情况下为Error实例)和解决状态存储在promise中。

此操作背后的主要思想是,将始终使用结果值来调用.then.catch处理程序,而不管.then()调用是在实现承诺之前还是之后进行的。这也允许多个处理程序。

未处理的错误是否仍会在内存中“挂起”,以等待其处理程序被注册?

如果您没有setTimeoutlet promise变量及其承诺对象和错误对象,则将立即对其进行垃圾收集。

,

直接回答您的问题:

这是否意味着一直以来该错误一直在内存中的某个地方,等待可能稍后再注册.catch处理程序的机会?

是的,我们有WeakMap个待处理的拒绝记录,用于跟踪已拒绝但未同步处理的承诺。 Chrome的功能类似(如果需要,我可以链接到它)。

但是如果它从未发生并且被拒绝的承诺数量增加了怎么办?

设计这些功能时的假设是,拒绝非常罕见,并且在特殊情况下适用-因此拒绝路径有点慢。但是,是的,理论上您可以创建很多“待定”拒绝。

未处理的错误是否仍会在内存中“挂起”,以等待其处理程序被注册?

我们只等待一个小记号-因此流程为:

  • 您创建了被拒绝的承诺
  • 它没有处理程序,因此将其放入WeakMap
  • 所有微任务都运行(process.nextTick / Promise.resolve.then)
  • 如果仍被拒绝,则是未处理的拒绝,它将记录到屏幕上/事件被触发。

也就是说,拒绝不会在内存中保留1000ms(计时器持续时间),而只会保留微任务运行所需的时间。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...