当您不再持有对 ES6-Promise 的引用时会发生什么情况
What happens to an ES6-Promise when you no longer hold a reference to it?
Background
从下面的代码中可以看到:
var foo1 = new Promise (function (resolve, reject){};
var foo2 = new Promise (function (resolve, reject) {
resolve('succes!');
});
var foo3 = new Promise (function (resolve, reject) {
reject(Error('Failure!'));
});
console.log (typeof foo1 === 'object'); // true
console.log (Object.getOwnPropertyNames(foo1)); // []
console.log (foo1.length); // undefined
console.log (foo1); // Promise { <pending> }
console.log (foo2); // Promise { 'succes!' }
console.log (foo3); // Promise { <rejected> [Error: Failure!] }
引用Promise
的变量引用了一个特殊的Promise
对象,该对象包含传递给Promise
构造函数的状态或结果。如果随后设置:
foo1 = null;
foo2 = null;
foo3 = null;
您无法再访问此状态或结果。
问题
在上述情况下,Promise
是否会被垃圾收集,如果没有,这不会造成内存泄漏的风险吗?
在上述情况下,
Promise
会被收集垃圾吗?
是的。在这方面,promise 对象就像所有其他对象一样。
一些实现(Firefox)确实有特殊行为,其中未处理的拒绝检测依赖于垃圾收集,但这并没有真正改变所收集的承诺对象的任何内容。
我问了另一个问题,因为我没有看到这个。但是这里的讨论,以及回答我的问题时出现的其他链接,并没有给出明确的答案。("是"和"否"都是作为答案给出的,并且没有足够的证据来知道谁是对的。
所以我设计了这个测试:
$ node --expose-gc
Welcome to Node.js v17.1.0.
Type ".help" for more information.
> const registry = new FinalizationRegistry(heldValue => { console.log(`finalizing with ${heldValue}`) });
> var stop = false; function loop(res) { if (stop) return res(); setTimeout((() => loop(res)), 3000); }
> var p = new Promise((res,rej) => loop(res)), q = p.then(()=>console.log('done')); registry.register(p, "pho", p); registry.register(q, "qux", q);
> p=q=null;
> gc()
undefined
> gc()
undefined
> gc()
undefined
> gc()
undefined
> gc()
undefined
> stop=true
true
done
> gc()
undefined
finalizing with qux
finalizing with pho
总结:p=q=null
之后,我不再提及任何承诺。因此,如果它们在解析之前是 gc'able,人们会期望在循环停止之前看到最终消息,第二个 Promise 记录"完成"。但人们看不到这一点。
不过,这还不是决定性的,因为大概一个内部 Node 注册表在 setTimeout 滴答作响时保存了对它们的引用,因此也保留了对 res
参数的引用,并通过它保留了对第一个 Promise 的引用。也许第一个承诺是对第二个承诺的引用。
我也试过:
> var p = new Promise((res,rej) => { }), q = p.then(()=>console.log('done')); registry.register(p, "pho", p); registry.register(q, "qux", q); q = null;
> gc()
undefined
> gc()
undefined
> gc()
undefined
> gc()
undefined
> p = null
null
> gc()
undefined
finalizing with qux
finalizing with pho
这证实了,只要你持有对第一个承诺的引用,附加到它.then(...)
承诺也会保持活动状态,即使你对后者没有任何明确的引用。但是,当你放弃对第一个承诺的引用时,即使尚未解决,它也会变得可收集,第二个承诺也是如此。
如果在最后一个示例中,我首先删除对p
的引用,保留对q
的引用,则p
变得可收集。(在这种情况下,对q
的引用并不能使p
保持活力。
- 在什么情况下需要同时使用compile&链接函数的角度
- 可以“;超级“;可以在子类的方法内部使用,在不直接引用的情况下调用相应的超类方法
- 在什么情况下,Array.observe的“add”事件会触发
- 用户单击带有哈希值的链接以访问该页面,如果禁用Javascript会发生什么情况
- 在什么情况下我们需要在javsacript中实现单例类
- 在什么情况下,应该.deep.equal失败,但使用JSON.stringify进行比较工作正常
- 在 301 重定向期间,Google Analytics cookie _ga会发生什么情况
- 当浏览器关闭时,运行Web Worker会发生什么情况
- 使用node.js模块,在什么情况下模块会被执行两次
- 更改 innerHTML 属性时处理程序会发生什么情况
- 如果在 JavaScript 中的 if 条件之后在执行块中使用两个等于而不是只有一个,会发生什么情况
- 如果取消对本地存储的写入,会发生什么情况
- 当您不再持有对 ES6-Promise 的引用时会发生什么情况
- 对垃圾收集的 HTTP 请求的 HTTP 响应会发生什么情况
- 更改对象的原型时会发生什么情况
- 如何在不丢失引用的情况下打开新选项卡
- 在不更改 A 引用的情况下执行数组 A = 数组 B 的最快方法
- 如果工作线程发布消息时主线程繁忙,会发生什么情况
- 在什么情况下浏览器拒绝继续调用 setInterval 回调
- 如果调用了JavaScript事件侦听器而缺少目标元素,会发生什么情况