CNode

setTimeout 和 process.nextTick 递归调用为什么不会栈溢出?

Jjiyinyiyong发布于14 年前最后回复14 年前9 回复7164 浏览0 收藏

代码

// Generated by CoffeeScript 1.4.0
var a, f, log;

a = 1;

log = console.log;

f = function(b) {
  log(b);
  return process.nextTick(function() {
    return f(b + 1);
  });
};

f(a);

居然就这么执行了.. 不是说 JS 没有尾递归优化的么, 而且作用域里的 b 不是也要保存的么... 可是没有栈溢出的报错

查看回复

回复 (9)

A
a272121742#1·14 年前

如果不用process.nextTick,为什么递归次数会出现以下结果: 1.如果是保存为文件,运行:永远是在17956次的时候停止? 2.如果是在node-shell里运行:则递归次数不固定,但会停止!

J
jiyinyiyong#3·14 年前

网上搜出来, 貌似和栈的深度有对应.. 没测试 https://groups.google.com/forum/?fromgroups=#!topic/nodejs-dev/KyBoGTAq1cQ

$ node --stack_size=2048


> var err, n=0; (function f(){ n++; try {f()} catch (e) {err=e}})(), [err.message, n]
[ 'Maximum call stack size exceeded', 21809 ]
$ node --stack_size=4096


> var err, n=0; (function f(){ n++; try {f()} catch (e) {err=e}})(), [err.message, n]
[ 'Maximum call stack size exceeded', 43654 ]
$ node --stack_size=8192


> var err, n=0; (function f(){ n++; try {f()} catch (e) {err=e}})(), [err.message, n]
Segmentation fault ( oops :-)
J
JacksonTian#4·14 年前

这玩意不算真正的递归调用吧。执行一次,将内容压入任务队列中,下次循环的时候取出来执行,然后重复。并不是在一次循环中完成的。

J
jiyinyiyong#5·14 年前
引用 JacksonTian这玩意不算真正的递归调用吧。执行一次,将内容压入任务队列中,下次循环的时候取出来执行,然后重复。并不是在一次循环中完成的。

就是说递归是不会压入队列了.. 那除此之外还有区别么, 比如压入队列的环境的内容, 是跟直接递归时一样的?

C
codekiller#6·14 年前

每次nexttick调用的匿名函数是新定义的,它在转调用的f,也就是你的f通过一个匿名函数调用f,中间间隔了一层,就不是递归调用了

C
codekiller#8·14 年前

这不是递归调用 你只是递归定义新函数而已

J
jiyinyiyong#9·14 年前
引用 codekiller这不是递归调用 你只是递归定义新函数而已

后续的 f 不是原先定义的那个 f 继续执行?

参与回复
登录后即可参与回复。登录