`process.nextTick`如何防止我的堆栈爆炸?

时间:2015-02-05 16:49:24

标签: javascript node.js recursion stack-overflow tail-recursion

我发现了一个写入文件的函数(here on 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在防止堆栈溢出方面发挥作用的情况确实存在(参见接受答案中的示例)。

1 个答案:

答案 0 :(得分:1)

如果你有一个同步调用自己的函数,比如说200k次,那么由于堆栈嵌套太深,代码会因错误而退出。 process.nextTick通过在每次迭代中清除callstack来避免类似于setTimeout(fn,0)的方式。它只是推迟执行传递的函数,直到下次eventloop运行。

更多阅读(但已过时):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(而异步,因此您引用的注释不正确。