Node.js: 是否对异步函数中的尾调用进行了优化?
Node.js: Are there optimizations for tail calls in async functions?
我正在使用 Node v8.10.0
- Node.js tail-call optimization: possible or not?
上述问题解释了 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
错误,但声明的变量存在于堆中,因此可以在保持堆栈信息完整的情况下进行垃圾回收。
我正在使用 Node v8.10.0
- Node.js tail-call optimization: possible or not?
上述问题解释了 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
错误,但声明的变量存在于堆中,因此可以在保持堆栈信息完整的情况下进行垃圾回收。