首页 > 解决方案 > 等待但从未解决/拒绝的承诺内存使用情况

问题描述

await既不解决也不拒绝(从不解决/未完成)的ing会Promise导致内存泄漏吗?

我在查看带有slorber/awesome-debounce-promise的 React 钩子时对此感到好奇,它创建了新的 Promise,但只解决了最后一个 Promise,因此留下了许多/最不稳定/未实现的。

标签: javascriptasync-awaites6-promise

解决方案


前言(你可能知道这个!):

await是使用 promise 回调的语法糖。(真的,真的,非常棒的糖。)async函数是 JavaScript 引擎为你构建承诺链等的函数。

回答:

相关的事情不是承诺是否被解决,而是承诺回调(以及它们引用/关闭的东西)是否保留在内存中。当 Promise 在内存中并且未解决时,它引用了它的回调函数,将它们保存在内存中。有两件事使这些引用消失了:

  1. 兑现承诺,或
  2. 释放所有对 Promise 的引用,使其符合 GC 的条件(可能,更多内容见下文)

在正常情况下,promise 的使用者将处理程序与 promise 挂钩,然后要么根本不保留对它的引用,要么只在处理程序函数关闭而不是其他地方的上下文中保留对它的引用。(而不是,例如,将 Promise 引用保存在一个长期存在的对象属性中。)

假设 debounce 实现释放了它对永远不会解决的 Promise 的引用,并且 Promise 的使用者没有在这个相互引用循环之外的某个地方存储引用,那么 Promise 和注册到它的处理程序(以及任何一旦释放对承诺的引用,它们拥有唯一的引用)都可以被垃圾收集。

这需要在实施方面相当小心。例如(感谢Keith将其标记出来),如果 Promise 使用其他 API 的回调(例如,addEventListener)并且回调关闭对 Promise 的引用,因为其他 API 具有对回调的引用,那防止所有对 Promise 的引用被释放,从而将 Promise 引用的任何内容(例如它的回调)保留在内存中。

因此,这将取决于谨慎的实施,并取决于消费者。可以编写保留对承诺的引用的代码,从而导致内存泄漏,但在正常情况下,我不希望消费者这样做。


推荐阅读