“process.nextTick”如何防止我的堆栈爆炸

How does `process.nextTick` keep my stack from blowing up?

本文关键字:我的 堆栈 何防止 process nextTick      更新时间:2023-09-26

我偶然发现了一个函数(在SO上),它可以写入文件,但确保不会覆盖文件:

function writeFile(i){
    var i = i || 0;
    var fileName = 'a_' + i + '.jpg';
    fs.exists(fileName, function (exists) {
        if(exists){
            writeFile(++i);
        } else {
            fs.writeFile(fileName);
        }
    });
}

下面有一条有趣的评论:

小调整:由于JavaScript不会优化尾部递归,所以将writefile(++i)更改为process.nextTick(function(i) {writefile(++i);});,这样可以防止在必须遍历大量文件名时堆栈爆炸。

请解释。process.nextTick如何防止烟囱爆炸?


更新:原来评论中的假设是错误的!无论如何,确实存在process.nextTick在防止堆栈溢出方面发挥作用的情况(请参阅公认答案中的示例)。

如果您有一个同步调用自己的函数,比如说,200k次,那么由于堆栈嵌套太深,代码将错误退出。process.nextTick通过在每次迭代中清除调用堆栈来避免类似于setTimeout(fn,0)的情况。它只是将传递函数的执行推迟到下一次事件循环运行时。

更多阅读(但已过期):http://howtonode.org/understanding-process-next-tick

落入此陷阱的示例函数:

(function doWork (i) {
    if (i === 0) return;
    console.log('Doing work!');
    doWork(--i);
}(2000000))

和process.nextTick:修复的相同功能

(function doWork (i) {
  if (i === 0) return;
  console.log('Doing work!');
  process.nextTick(function () {
    doWork(--i);
  });
}(2000000))

然而,在您的情况下,这不会是一个问题,因为由于fs.exists(,代码是异步的,因此您引用的注释是不正确的。