Javascript 脚本和setTimeout/setInterval如何在NodeJS中协同工作?
阅读全文,我想知道setTimeout和setInterval实际上是如何工作的 页面上说NodeJS首先运行给定的脚本,暂时不使用REPL,然后进入事件循环。但是,如果我在脚本中调用setTimeout,并期望它在脚本仍在运行时触发,该怎么办?这不是正常情况吗?根据描述,在主脚本结束之前不会触发计时器回调,这听起来真的很奇怪Javascript 脚本和setTimeout/setInterval如何在NodeJS中协同工作?,javascript,node.js,Javascript,Node.js,阅读全文,我想知道setTimeout和setInterval实际上是如何工作的 页面上说NodeJS首先运行给定的脚本,暂时不使用REPL,然后进入事件循环。但是,如果我在脚本中调用setTimeout,并期望它在脚本仍在运行时触发,该怎么办?这不是正常情况吗?根据描述,在主脚本结束之前不会触发计时器回调,这听起来真的很奇怪 对于那些感兴趣的人来说,这里是NodeJS外部偶数循环,实际上有两个嵌套循环:[EDIT]哼哼。在阅读您最初的帖子时,我想我知道您有什么问题。您在帖子中提到了nodejs
对于那些感兴趣的人来说,这里是NodeJS外部偶数循环,实际上有两个嵌套循环:[EDIT]哼哼。在阅读您最初的帖子时,我想我知道您有什么问题。您在帖子中提到了nodejs,这意味着您可能正在编写服务器代码 如果您对服务器端JavaScript不太熟悉,或者对php服务器不太熟悉,那么您可能会感到非常困惑 对于php服务器,请求将创建一个新线程来处理它,当您调用的主脚本结束时,该线程将被终止,除侦听请求的Web服务器(如nginx或apache)外,服务器上不会运行任何其他线程 有了nodejs,情况就不同了。主线程是单独的,并且始终在运行。因此,当一个请求到达时,回调被触发,但它们仍然在那个单线程中。否则:主脚本永远不会结束,除非您杀死它或服务器崩溃: 嗯,这是正确的。由于JavaScript的单线程特性,如果计时器在主线程繁忙时结束,计时器的回调将等待 当你这样做的时候
setTimeout(callback, 1000)
你不是说我希望这个回调在1s内被调用,但实际上我希望这个回调至少在1s内被调用
John Resig的这篇文章是一篇优秀的阅读材料,它详细介绍了JavaScript计时器的细节。您在帖子中提到了nodejs,这意味着您可能正在编写服务器代码 如果您对服务器端JavaScript不太熟悉,或者对php服务器不太熟悉,那么您可能会感到非常困惑 对于php服务器,请求将创建一个新线程来处理它,当您调用的主脚本结束时,该线程将被终止,除侦听请求的Web服务器(如nginx或apache)外,服务器上不会运行任何其他线程 有了nodejs,情况就不同了。主线程是单独的,并且始终在运行。因此,当一个请求到达时,回调被触发,但它们仍然在那个单线程中。否则:主脚本永远不会结束,除非您杀死它或服务器崩溃: 嗯,这是正确的。由于JavaScript的单线程特性,如果计时器在主线程繁忙时结束,计时器的回调将等待 当你这样做的时候
setTimeout(callback, 1000)
你不是说我希望这个回调在1s内被调用,但实际上我希望这个回调至少在1s内被调用
John Resig的这篇文章是一篇优秀的阅读材料,它详细介绍了JavaScript的计时器如果节点是单线程的,那么它的v8引擎总是在进入下一个脚本之前执行当前脚本。因此,当我们用主脚本启动节点服务器时,它首先加载、解析、编译并执行该脚本,然后再运行其他任何操作。只有当当前正在运行的脚本命中I/O调用时,它才会跳转到事件循环的后面,给其他脚本或setTimeout回调一个执行的机会。这正是JavaScript引擎的本质,也是Node不适合长时间运行、内存中CPU密集型任务的原因
正如@atomrc在他的回答中所说,setTimeout和setInterval只是提示node在超时后运行回调,没有任何保证。鉴于node是单线程的,它总是在进入下一个脚本之前执行当前脚本。因此,当我们用主脚本启动节点服务器时,它首先加载、解析、编译并执行该脚本,然后再运行其他任何操作。只有当当前正在运行的脚本命中I/O调用时,它才会跳转到事件循环的后面,给其他脚本或setTimeout回调一个执行的机会。这正是JavaScript引擎的本质,也是Node不适合长时间运行、内存中CPU密集型任务的原因 正如@atomrc在他的回答中所说的,setTimeout和setInterval只是提示节点在超时后运行回调,没有任何保证 但是,如果我在脚本中调用setTimeout,并期望它在脚本仍在运行时触发,该怎么办 你没料到。您希望同步代码在超时发生之前以完成方式运行 如果脚本仍然在运行,因为它正在执行阻塞操作-它挂起-那么超时回调没有机会执行,它将等待。那是 这正是我们需要编写非阻塞代码的原因 这不是正常情况吗 不会。大多数情况下,没有JS在执行,事件循环处于空闲状态,而可能有后台任务在执行繁重的任务 但是,如果我在脚本中调用setTimeout,并期望它在脚本仍在运行时触发,该怎么办 你没料到。您希望同步代码在超时发生之前以完成方式运行 如果脚本仍然在运行,因为它正在执行阻塞操作-它挂起-那么超时回调没有机会执行,它将等待。这正是我们需要编写非阻塞代码的原因 这不是正常情况吗 不会。大多数情况下,没有JS在执行,事件循环处于空闲状态,而可能有后台任务在执行繁重的任务。让我们通过示例来实现这一点 这将在那里打印hi 发生了什么 该脚本将一直处理到最后一行,当它找到一个计时器函数时 它将把它添加到队列中,队列调度器稍后将在执行结束时处理该队列 循环队列=>[setTimeout] 在退出之前,应该有一个调度程序,某种循环来检查我们是否 在队列中有一些东西并处理它们,然后一旦队列超出所有计时器,循环就结束了 将退出 假设我们在setInterval内调用setTimeout 循环队列=>[setInterval] 1000毫秒后 将激发setInterval,并将内部setTimeout添加到队列中 循环队列=>[setTimeout,setInterval] 现在我们回到主回路,它将再等待500毫秒 触发内部setTimeout函数,然后将其从队列中删除 因为setTimeout应该运行一次 循环队列=>[setInterval] 回到主循环,队列中仍然有项目,因此它将等待 再发射500毫秒,再发射500+500=1000毫秒 内部setTimeout函数将再次添加到队列中 循环队列=>[setTimeout,setInterval] 再次回到主队列并再次 这就是定时器的工作原理,它们不是用来处理阻塞代码的,而是 以一定间隔运行代码的方法
setInterval(function(){
// do something long running here
while (1) {}
setTimeout(function(){
print('hi')
}, 500);
}, 1000);
主循环将在此阻塞,内部超时不会添加到队列中,因此
这是个坏主意
nodej和事件循环通常很适合网络操作,因为它们在运行时不会阻塞
例如,与select一起使用
setInterval(function(){
// check if socket has something
if (socketHasData( socket )){
processSocketData( socket );
}
// do something else that does not block
// maybe schedule another timer here
print('hello');
}, 1000);
libuv是nodejs中使用的事件循环,它使用线程来处理一些事件
阻止诸如IO操作、打开/读取/写入文件之类的操作
这将在那里打印hi
发生了什么
该脚本将一直处理到最后一行,当它找到一个计时器函数时
它将把它添加到队列中,队列调度器稍后将在执行结束时处理该队列
循环队列=>[setTimeout]
在退出之前,应该有一个调度程序,某种循环来检查我们是否
在队列中有一些东西并处理它们,然后一旦队列超出所有计时器,循环就结束了
将退出
假设我们在setInterval内调用setTimeout
循环队列=>[setInterval]
1000毫秒后
将激发setInterval,并将内部setTimeout添加到队列中
循环队列=>[setTimeout,setInterval]
现在我们回到主回路,它将再等待500毫秒
触发内部setTimeout函数,然后将其从队列中删除
因为setTimeout应该运行一次
循环队列=>[setInterval]
回到主循环,队列中仍然有项目,因此它将等待
再发射500毫秒,再发射500+500=1000毫秒
内部setTimeout函数将再次添加到队列中
循环队列=>[setTimeout,setInterval]
再次回到主队列并再次
这就是定时器的工作原理,它们不是用来处理阻塞代码的,而是
以一定间隔运行代码的方法
setInterval(function(){
// do something long running here
while (1) {}
setTimeout(function(){
print('hi')
}, 500);
}, 1000);
主循环将在此阻塞,内部超时不会添加到队列中,因此
这是个坏主意
nodej和事件循环通常很适合网络操作,因为它们在运行时不会阻塞
例如,与select一起使用
setInterval(function(){
// check if socket has something
if (socketHasData( socket )){
processSocketData( socket );
}
// do something else that does not block
// maybe schedule another timer here
print('hello');
}, 1000);
libuv是nodejs中使用的事件循环,它使用线程来处理一些事件
阻止IO操作、打开/读取/写入文件等操作不幸的是,您做出了一些错误的假设:-我既没有实现服务器,也不习惯PHP。我想要了解的是,如果是单线程的,那么主脚本中的计时器回调集如何在NodeJS中的每个触发器上运行?我研究了NodeJS源代码一段时间,但它的工作原理一点也不明显。在我看来,在主脚本完成之前,似乎不会触发回调。Oups太糟糕了:/n我认为混淆之处在于您所称的主脚本。我不确定我是否明白你在说什么。注意:计时器在
浏览器是一个不同的东西,因为有几个线程涉及,而NodeJS不使用,从我看到的。不过,即使在浏览器中,这也只能在JS引擎支持在任意时间插入回调的情况下工作,或者在脚本运行时它们永远不会运行。顺便说一句,nodejs的源代码很容易阅读。我不确定我能做到这一点!!!关于主脚本:请参见链接的描述。它说NodeJS首先加载给定的脚本并运行它,然后启动事件循环。不幸的是,你做了一些错误的假设:-我既没有实现服务器,也不习惯PHP。我想要了解的是,如果是单线程的,那么主脚本中的计时器回调集如何在NodeJS中的每个触发器上运行?我研究了NodeJS源代码一段时间,但它的工作原理一点也不明显。在我看来,在主脚本完成之前,似乎不会触发回调。Oups太糟糕了:/n我认为混淆之处在于您所称的主脚本。我不确定我是否明白你们在说什么。注意:浏览器中的计时器是一个不同的东西,因为有几个线程涉及,而NodeJS并没有使用,从我所看到的。不过,即使在浏览器中,这也只能在JS引擎支持在任意时间插入回调的情况下工作,或者在脚本运行时它们永远不会运行。顺便说一句,nodejs的源代码很容易阅读。我不确定我能做到这一点!!!关于主脚本:请参见链接的描述。它说NodeJS首先加载给定的脚本并运行它,然后在该脚本结束后启动事件循环。当脚本仍在运行时,您到底理解什么?如前所述。NodeJS将处理初始脚本,然后转到事件循环。如果初始脚本从未返回(例如,有自己的循环,但希望使用setTimeout),该怎么办?是的,如果脚本阻塞-挂起-则超时回调将永远无法执行。这正是我们需要编写非阻塞代码的原因。当脚本仍在运行时,您到底理解了什么?如前所述。NodeJS将处理初始脚本,然后转到事件循环。如果初始脚本从未返回(例如,有自己的循环,但希望使用setTimeout),该怎么办?是的,如果脚本阻塞-挂起-则超时回调将永远无法执行。这正是我们需要编写非阻塞代码的原因。假设您运行一个脚本来测试某些东西。它需要一段时间来运行,并希望显示进度。为此,它使用计时器将进度节拍合并为一个不太小的间隔。如果您是对的,在测试脚本结束之前,永远不会显示进度输出。那么设置超时有什么好处呢?是的。如果测试代码同步运行,它还需要同步写入进度输出。您仍然可以使用Date来计算时间。当需要使用setTimeout时,is必须异步运行测试,即至少在其自己的进程中运行每个测试。它需要一段时间来运行,并希望显示进度。为此,它使用计时器将进度节拍合并为一个不太小的间隔。如果您是对的,在测试脚本结束之前,永远不会显示进度输出。那么设置超时有什么好处呢?是的。如果测试代码同步运行,它还需要同步写入进度输出。您仍然可以使用Date来计算时间。当需要使用setTimeout时,is必须异步运行测试,即至少在其自己的进程中运行每个测试。