【问题标题】:Does JavaScript promise create memory leaks when not rejected or resolved?JavaScript 承诺在没有被拒绝或解决时会造成内存泄漏吗?
【发布时间】:2015-10-09 20:28:17
【问题描述】:

我需要以“并行”方式执行异步函数,并以最佳结果继续执行程序。因此我写了这样的东西:

var p = [];

for (var i = 0; i < 10; ++i) (function (index) {
  p.push(new Promise(function (resolve, reject) {
    setTimeout(function () {
      var success = Math.random() > 0.7;

      console.log("Resolving", index, "as", success ? "success" : "failure");

      success && resolve(index);
    }, Math.random() * 5000 + 200);
  }));
})(i);

Promise.race(p).then(function (res) {
  console.log("FOUND", res);
}).catch(function (err) {
  console.log("ERROR", err);
});

现在,我想知道在使用 Promise 时这是否是一种好习惯?不是更频繁地解决或拒绝它们然后任何东西都会造成内存泄漏吗?他们最终每次都被 GC 处理了吗?

【问题讨论】:

标签: javascript memory-leaks es6-promise


【解决方案1】:

导致内存泄漏的唯一原因是p 是一个全局变量。最后设置p = null;,或者避免使用全局变量:

var console = { log: function(msg) { div.innerHTML += msg + "<br>"; }};

Promise.race(new Array(10).fill(0).map(function(entry, index) {
  return (function(index) {
    return new Promise(function(resolve) {
      setTimeout(function() {
        var success = Math.random() > 0.7;
        console.log((success? "R":"Not r") + "esolving "+ index +".");
        success && resolve(index);
      }, Math.random() * 5000 + 200);
    });
  })(index);
})).then(function (res) {
    console.log("FOUND: " + res);
}).catch(function (err) {
    console.log("ERROR: " + err);
});
&lt;div id="div"&gt;&lt;/div&gt;

当您的 JS 和浏览器(此处为 setTimeout)不再引用它们时,Promise 是垃圾和循环收集。

只要p 中的一个条目成功或某事失败,以较早者为准,setTimeout 将在 5.2 秒后释放所有内容。然后 JavaScript 会愉快地对 Promise 进行垃圾收集,无论它们是否已被解决、被拒绝或两者都没有。没有伤害。

您唯一要避免的是垃圾收集 rejected 承诺,因为这可能会触发浏览器警告,因为它表明存在 Web 编程错误。

当然,有 30% 的可能性它们都没有解决,在这种情况下会泄漏(直到您关闭选项卡)。

这是好的设计吗?

我认为这取决于函数在做什么。如果它们是轻量级的,那么我认为没有问题。如果他们正在进行大量计算或有副作用,那么他们希望提供一些 API 来取消操作,以帮助节省资源。

【讨论】:

  • Promise.race 不会对剩余的 Promise 进行垃圾收集,并且重复运行 Promise.race 并使用无法解决的 Promise 是已知的内存泄漏。见github.com/nodejs/node/issues/17469
  • @brainkim 这是一种实现方式,听起来像是 V8 中的 agree it's a bug
  • 如果您检查 Chromium 上的相关错误,您将看到没有这样的协议。 bugs.chromium.org/p/v8/issues/detail?id=9858#c4
  • @brainkim 你是对的。我已经有一段时间没有看到这个了。当我回答时,我可能误读了success &amp;&amp; resolve(index)。随意添加更好的答案。
  • 试图挽救答案。随意添加具有更多信息的竞争答案,我会投票。
猜你喜欢
  • 2013-12-02
  • 2023-03-26
  • 2018-07-25
  • 2022-01-06
  • 2015-09-04
  • 2013-06-22
  • 2018-06-17
  • 1970-01-01
相关资源
最近更新 更多