由于许多node.js脚本遵循异步执行模式(以下示例),因此它们如何知道何时停止?
在以下代码中,节点如何确定在处理writeFile和适当注册回调之后,在回调运行之前,该进程应保持活动状态?
fs = require('fs'); fs.writeFile('foo', 'cat', function() { console.log('wrote to foo!'); fs.readFile('foo', 'utf8', function(err, data) { console.log(data); }); });
节点跟踪所有未完成的工作请求。您的fs.writefile()调用为I / O创建工作请求,并将您的回调添加到该请求。节点在启动I / O活动的同时将工作请求保存到其表中。到达函数末尾时,代码执行将退出。(但您的内存/变量/等仍然存在)
稍后,I / O完成,并且节点将工作请求从表中取出。它看到附加到请求的回调,因此使用I / O请求的结果调用该函数。您的全局数据仍然存在,并且闭包中的任何变量仍然存在,因此在您的代码中似乎从未停止过。
如果您什么也不做,不要再发出任何请求,那么当您从函数返回时,节点将停止,因为这样队列中将不再有任何剩余的请求。
因此,节点“知道”继续运行,因为它跟踪其表中的活动工作请求,并且直到所有排队的工作都完成并且这些表为空时才会停止。
请注意,“排队工作”可能包括诸如等待计时器或等待网络数据到达之类的事情。您发出一个请求,要求您说“如果以后有事请给我打电话”。
setTimeout()也是一个工作请求(如果您斜视一下)。使用计时器,您知道会发生什么以及何时发生。使用setTimeout()只会发生一个“事情”。节点将仅对您的回调进行一次调用,然后“忘记”工作请求。相反,如果您使用setInterval(),则创建了一个持久性工作请求。节点将“保留”其表中的工作请求,并将反复调用回调,直到您取消该请求为止。
net.Server.listen()是另一个工作请求,它是一个持久性工作请求。您不知道何时调用回调或调用多少次,因为这取决于连接到服务器的远程客户端。节点将工作请求保持在其表中,直到您取消该请求为止。