我认为我误解了setTimeout
在JavaScript中的确切含义。我有这个脚本:
function recursiveFibonacci(n) {
if ( n === 0 ) {
return 1;
} else if ( n === 1 ) {
return 1;
} else {
return recursiveFibonacci(n-1) + recursiveFibonacci(n-2);
}
}
setTimeout( () => {console.log("one second");}, 1000);
console.log(recursiveFibonacci(42));
我期望发生的是recursiveFibonacci开始在斐波那契序列中的第43个值上开始。这在我的电脑上大约需要4秒钟。因此,在1秒钟的工作后,评估将被中断,控制台将记录:
one second
然后大约3秒后登录:
433494437
相反,发生的事情是,在4秒后,控制台记录:
433494437
one second
一下子全部。为什么会这样?如何让setTimeout
工作?如果JavaScript解释器实际上没有被setTimeout
中断,而是,如果它完成其他作业,那么它将等到给定的时间量已经过去,然后再调用给定的函数?
修改
我发现这个工具对于理解相关概念非常有用:
答案 0 :(得分:6)
node.js中的Javascript是事件驱动和单线程的。由于您的reverseFibonacci()
函数是同步的,因此在完成之前不允许任何其他内容运行。
因此,即使计时器触发并且计时器回调被放入内部nodejs事件队列,JS解释器也无法到达事件队列中的下一个事件,直到reverseFibonacci()
函数完成。 / p>
setTimeout()
不会中断当前运行的Javascript。相反,它将事件放入事件队列中,当完成当前运行的Javascript时,JS解释器将把下一个事件拉出事件队列并运行它。
因此,您的方案中的事件顺序如下:
reverseFibonacci()
reverseFibonacci(42)
完成了运行。计时器安排setTimeout()
在预定时间后尽快运行,但如果Javascript解释器正在忙于运行其他代码,则它们不会中断该代码。计时器系统将一个事件放入事件队列,当其他代码完成时,Javascript解释器将把下一个事件从事件队列中拉出并运行它(你的计时器回调将被调用)。
答案 1 :(得分:1)
这是因为你的功能可以同步工作。
node event loop的性质是异步的。只要你执行完成执行或者你将执行异步 - nextTick
将被调用。而且很可能第一项是你的setTimout函数。
以下是预期异步块的示例,它可以按预期工作:
function sleep(ms) {
return new Promise( (resolve, reject) => {
setTimeout(resolve, ms);
});
}
async function recursiveFibonacci(n) {
await sleep(10);
if ( n === 0 ) {
return 1;
} else if ( n === 1 ) {
return 1;
} else {
return await recursiveFibonacci(n-1) + await recursiveFibonacci(n-2);
}
}
setTimeout( () => {console.log("one second");}, 1000);
recursiveFibonacci(25).then(console.log);