await
Promise
既不解决也不拒绝(从不解决/未实现)会导致内存泄漏吗?
我对使用slorber/awesome-debounce-promise的React钩子感到好奇,该钩子创建了新的承诺,但仅解决了最后一个,因此使很多/大多数人不安/未实现。 < / p>
答案 0 :(得分:14)
序言(您可能知道这一点!):
await
是用于使用promise回调的语法糖。 (真的,真的,真的很好糖。) async
函数是JavaScript引擎为您构建承诺链等的函数。
答案:
相关的问题不在于是否实现了诺言,而是是否在内存中保留了诺言回调(以及它们所引用/结束的事情)。当promise在内存中并且尚未解决时,它会引用其回调函数,将其保留在内存中。有两点使这些引用消失了:
在通常情况下,promise的使用者将处理程序挂接到该promise,然后要么根本不保留对它的引用,要么仅在处理程序功能关闭且上下文中保留对它的引用。没有其他地方。 (而不是例如,将promise引用保留在长期存在的对象属性中。)
假设debounce实现释放了对它永远不会实现的promise的引用,并且promise的使用者没有在此相互引用周期之外的某个地方存储引用,那么promise和处理程序将向其注册(一旦发布了对诺言的引用,所有它们拥有的唯一引用都可以被垃圾回收。
在实现方面需要相当的谨慎。例如(感谢Keith进行举报),如果promise使用其他API的回调(例如addEventListener
),并且该回调在对由于其他API都具有对回调的引用,因此可以防止释放对承诺的所有引用,从而将承诺所引用的任何内容(例如其回调)保留在内存中。
因此,这将取决于实现的谨慎性,并取决于消费者。可能会编写代码来保留对Promise的引用,从而导致内存泄漏,但是在正常情况下,我不希望消费者这样做。
答案 1 :(得分:5)
我使用以下结构进行了一些测试:
function doesntSettle() {
return new Promise(function(resolve, reject) {
// Never settle the promise
});
}
let awaited = 0;
let resolved = 0;
async function test() {
awaited++;
await doesntSettle();
resolved++;
}
setInterval(() => {
for (let i = 0; i < 100; ++i) {
test();
}
}, 1);
在此处实现:https://codesandbox.io/s/unsetteled-awaited-promise-memory-usage-u44oc
在Google Chrome中运行just the result frame表示在开发工具的“内存”标签(但不在“性能/ JS堆”标签下)中的内存使用量不断增加,表明存在泄漏。执行此操作但兑现承诺并没有泄漏。
运行此增加的内存使用量增加了1-4MB /秒。停止运行GC并不能释放其中的任何内容。