这个函数能被垃圾回收吗?

20

考虑这块蛋糕…呃,代码:

'use strict'

function doWork () {
  return new Promise(function (resolve, reject) {
    // work work work...
    // Done! But... where's the resolve() ???
  })
}

doWork().then(function doMoreWork () {
  // Some more work to do...
})

一旦 Promise 构造函数中的函数执行完毕...

  1. Promise 对象是否可被垃圾回收?
  2. doMoreWork() 是否可被垃圾回收?

我猜想 doMoreWork() 无法直接进行 GC,因为 Promise 保留了对它的引用,但是一旦 Promise 函数体执行结束并将执行上下文返回给上层(?)作用域,堆栈展开(因为这里没有更多的语句需要执行),Promise 就变得不可达,从而可以进行垃圾回收。

你能确认我对这个主题的理解是否正确吗?

我如何通过实验证明这种行为? 换言之,我如何监视何时及其它哪些对象正在进行 GC 运算?我纯粹在 Node.js 中进行开发,如果这有任何区别。


您的意思是您的代码从不调用 resolve() 吗?是的,那种情况下,您所有的对象都会立即受到垃圾回收的影响。 - Bergi
3个回答

7

没有任何引用指向该Promise,因此它将被垃圾回收。Promise是唯一保留对函数doMoreWork引用的对象,因此它也将被垃圾回收。

我如何实证观察这种行为?换句话说,我如何监测哪些对象正在进行垃圾回收以及何时进行垃圾回收?如果开发环境为Node.js,是否会有所不同?

V8中的垃圾回收器并不一定会回收对象。例如,如果这是您的整个程序,则首先运行任何GC都是浪费时间。


0
  1. Promise对象是可收集的,如果没有指向它的引用。如果使用doWork().then(...),则会创建一个临时引用。因此,在.then不再阻塞之前,对象有一个引用,因此无法被收集。
  2. 你是对的,doMoreWork也是不可收集的,因为Promise对象有一个对它的引用。

语句doWork().then(...)可以替换为

new Promise(function (resolve, reject) {
  // work work work...
}).then(function doMoreWork () {
          // Some more work to do...
        })

你可以想象自己直接使用Promise对象,因此“Upper”范围是对象被使用的地方。

当没有更多引用时,通常会收集对象。即使代码在Promise中,它也只是一个对象,并且调用then是链接的,因此对象正在被使用。


1
我认为Esailija的答案应该是正确的,但是如果不知道Promise的实现方式就无法证明。 Promise被创建后,在其上执行了单个.then()调用,然后根据代码,它未被使用,因此Promise和then()的参数都可以被回收利用。但是,如果您的Promise实现保留了某种内部列表或表格来存储已创建的Promise呢?也许在解决后会释放它们;也可能永远不会。我猜他们不会以这种方式编写Promise实现;但是没有证据。无论哪种方式,您的JS程序都无法区分它们的差异。 - OsamaBinLogin

0

要查看一个对象是否可以进行垃圾回收,您可以创建一个测试并查找内存泄漏(通过任务管理器)。如果您的代码编写正确,所有内容都会被回收。


我认为主要的关注点不是内存泄漏,而是doMoreWork函数的代码执行。有没有保证它会被执行?因为如果被垃圾回收了,它就不会被执行。 - humkins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接