javascript - 在许多 promise 链之间共享全局已解决的 promise 会导致内存泄漏或性能下降吗?

标签 javascript memory-leaks bluebird es6-promise

我经常会遇到这种情况:

function makeSureDataWasFetched () {
  if (dataAlreadyFetched) {
    // Creating a new empty resolved promise object and returning it
    // to keep the function interface consistent
    return Promise.resolve()
  } else {
    return fetchData()
  }
}


因此,为了避免每次都重新创建一个新的空的已解决承诺对象,我一直在考虑共享一个唯一的全局已解决承诺的想法。

const resolved = Promise.resolve()

// then, re-use this resolved promise object all over the place
function makeSureDataWasFetched () {
  if (dataAlreadyFetched) {
    // Return the shared resolved promise object,
    // sparing the creation of a new resolved promise object
    return resolved
  } else {
    return fetchData()
  }
}

function makeSureSomethingElseWasFetched () {
  if (thatSomethingElseWasAlreadyFetched) {
    return resolved
  } else {
    return fetchSomethingElse()
  }
}

// etc


在整个应用程序中都引用了此已解决的承诺,因此永远不会对其进行垃圾回收。
因此,如果它对使用它的承诺链保持某种参考,那么那些链也不会被垃圾收集,那会造成内存泄漏,对吗?

所以我的问题是:这种全球解决的承诺是否会引用Bluebird实施中所有依赖的承诺链?在香草ES6中承诺吗?
如果不是,那会不会在性能方面抵消每次创建新的已解决承诺的剩余成本?

最佳答案

将在许多承诺链之间共享全球已解决的承诺
  造成内存泄漏或性能下降?


没有。

重用和共享全局解析的承诺只会使单个全局解析的承诺不会被垃圾回收。它不会影响可能链接到其上的其他promise的垃圾回收。当无法正常访问它们时,将对它们进行垃圾收集。

现在,尚不清楚完全共享全球解决的承诺有什么优势。不需要它。每当您想要一个已经解决的承诺时,都可以使用Promise.resolve()创建一个承诺,然后您的代码就不再依赖于共享的全局变量,而可以更加模块化。


  所以我的问题是:这种全球解决的诺言能否保持
  引用蓝鸟中所有依赖的诺言链
  实施?


没有。


  在香草ES6中承诺吗?


没有。


  如果不是这样,那会否在性能上产生不利的平衡
  每次都可以节省创建新的已承诺的成本吗?


您正在询问过早的微优化,这绝不是一个好主意。如果在将来的某个时候,您想完全优化代码的性能,那么您将进行剖析和评估,我可以向您保证,您将找到100项可以从事的工作,这对代码的影响远不止于尝试。分享全球性的坚定承诺。



为了帮助您了解谁对promise链接中的内容以及何时可以进行垃圾回收的引用,让我描述一下链接的工作方式。假设您有以下代码:

f1().then(f2).then(f3)


f1f2都返回诺言,我们将其称为P1P2

因此,这是进度:


调用f1(),它将返回一个承诺P1
呼叫P1.then(f2)会返回一个新的承诺,我们将呼叫P3
呼叫P3.then(f3)会返回一个新的承诺,我们将呼叫“ P4”。
然后,在将来的某个时刻,解析P1并触发它调用其.then()处理程序。
f2被调用并返回promise P2
当promise .then()代码的内部从f2 .then()处理程序获取返回值作为返回值时,它将检测到该返回值是一个promise,然后将新的promise P2链接到。它通过将自己的P3处理程序添加到.then()来做到这一点,以便它可以跟踪其状态。在P2内部,它将这个新的P3处理程序添加到可以解析.then()之前必须发生的事情的列表。请注意,在P3P2之间没有直接引用。他们甚至彼此之间没有直接引用。而是P3等待特定的P3处理程序(恰好附加到.then())被调用。
然后,在将来的某个时间P2解决。
这将调用在步骤6中建立的内部P2处理程序,并清除对该.then()处理程序的任何引用。这告诉.then()现在可以解决自身问题,并且将其间接引用取消链接到P3。此时,此诺言链中再也没有任何对P2的引用,因此,如果在代码的其他地方没有其他引用,可以对其进行GC处理。
P2解析时,它将调用其P3处理程序,该处理程序将执行.then(),告诉您的代码Promise链现在已完成。


因此,从这开始,我希望您能看到链接的诺言实际上并未存储彼此的引用。父承诺在子承诺上以f3处理程序结束,这使子承诺在调用.then()处理程序和调用.then()处理程序之前不会被GC,即使两个承诺之间的间接连接也是如此。断开,并且每个都可独立用于GC(只要其他代码中没有其他引用)。

根据您的问题,如果.then()恰好是您已共享的全局承诺,那么第6步将向其添加P2处理程序,该处理程序将在下一个滴答中被调用(因为基础承诺已被解决) ),并且一旦调用.then()处理程序,就不再有与.then()的连接了,因此无论它是否是持久全局变量都没有关系。

关于javascript - 在许多 promise 链之间共享全局已解决的 promise 会导致内存泄漏或性能下降吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40683818/

相关文章:

javascript - 如何在React中结合Material-UI的snackbar和input组件?

javascript - HTML 拖放持久化

JavaScript 对象从一个方法调用另一个方法

javascript - 如何用另一个替换输入值中的字符?

c# - WPF 组合框 "leaks"内存

c# - 当 SSL 和客户端证书与 HttpWebRequest 对象一起使用时发生内存泄漏

JavaScript Promise 依赖处理

javascript - 解决带有嵌套 promise 的对象的美丽方法?

java - 如何调试堆转储中的异常实例没有入站引用的内存泄漏?

javascript - Bluebird 中 Promise 链数组的串行执行