递归结合setTimeout异常:为何数字打印无法正常终止?
递归定时器函数无限打印问题排查
我需要编写一个递归函数,实现每隔1秒打印1到10的数字。尽管已编写递归退出条件,但当前函数打印数字从1开始,在达到10后仍继续无限打印,请问问题出在哪里?
原代码
function printNumbers2(from, to) { let number = from; if (number == to) { return number; } else { return setTimeout(() => { console.log(number); number++; printNumbers2(number); }, 1000); } } console.log(printNumbers2(1, 10));
运行结果
Timeout { _idleTimeout: 1000, _idlePrev: [TimersList], _idleNext: [TimersList], _idleStart: 15, _onTimeout: [Function (anonymous)], _timerArgs: undefined, _repeat: null, _destroyed: false, [Symbol(refed)]: true, [Symbol(kHasPrimitive)]: false, [Symbol(asyncId)]: 2, [Symbol(triggerId)]: 1 } 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
问题分析
- 递归调用未传递
to参数:函数定义需要from和to两个参数,但递归时只传了number,导致后续调用中to的值为undefined。此时退出条件number == to永远不成立(数字与undefined无法相等),递归无法终止,会无限执行。 - 退出逻辑遗漏目标值打印:原代码中
number == to时直接返回,这会导致目标值10无法被打印——因为只有else分支才会执行打印和递归操作。实际运行中能打印10,是因为当number为9时进入else,打印9后number变为10,接着调用printNumbers2(10),此时to是undefined,所以又进入else分支打印了10,随后number变为11,继续无限递归。
修正后的代码
function printNumbers2(from, to) { let number = from; // 先打印当前数字,确保目标值10也能被输出 console.log(number); // 严格判断当前数字是否等于目标值,满足则终止递归 if (number === to) { return; } // 1秒后递归调用,必须传递下一个数字和目标值to setTimeout(() => { printNumbers2(number + 1, to); }, 1000); } printNumbers2(1, 10);
修正说明
- 递归调用时始终传递
to参数,保证每次调用都能正确判断终止条件; - 调整执行顺序,先打印当前数字再判断终止,确保目标值10被输出;
- 使用
===严格相等运算符,避免类型隐式转换带来的判断误差。
内容的提问来源于stack exchange,提问作者Valentina
相关产品推荐
相关产品推荐

