Node.js: 是否对异步函数中的尾调用进行了优化?

Node.js: Are there optimizations for tail calls in async functions?

我正在使用 Node v8.10.0

上述问题解释了 Node.js 如何不再支持 TCO。不过,我最近遇到了这样一个函数的问题:

async function processBatch(nthBatch) {
    // do a bunch of async work and build up variables
    await processBatch(nthBatch + 1);
}

代码有内存泄漏,通过将其更改为:

立即得到修复
async function processBatch(nthBatch) {
    // do a bunch of async work and build up variables
    return processBatch(nthBatch + 1);
}

令我惊讶的是,它确实有效,因为在上述问题中,它清楚地解释了 Node 8.x 不支持 TCO。那么,是否有什么特别的事情可以在这里实现 TCO?或者是因为它在引擎盖下使用生成器并且 return 将生成器标记为已完成,因此可以丢弃堆栈?

async function processBatch(nthBatch) {
    // do a bunch of async work and build up variables
    await processBatch(nthBatch + 1);
}

此代码段导致内存泄漏,因为无法对注释中声明的变量进行垃圾回收,因为解释器不知道它们将不再需要。例如解释器此时不知道 await 之后没有一行可能需要所有这些声明的变量。

async function processBatch(nthBatch) {
    // do a bunch of async work and build up variables
    return processBatch(nthBatch + 1);
}

在这个例子中,函数被返回,所以垃圾收集器可以安全地清理方法中声明的变量。请注意,堆栈会保留下来,如果此递归函数有太多迭代,则会抛出 Maximum call stack size exceeded 错误,但声明的变量存在于堆中,因此可以在保持堆栈信息完整的情况下进行垃圾回收。