问题描述
我知道 NodeJS 事件循环从事件队列中收集任务并将控制权转移到任务的回调。任务完成后,任务从事件循环中转移控制权。
因此,我认为实际上返回回调是一个从 Task 获得控制权的 Event Loop。
这是正确的想法吗?
另外,如果对于Event Loop中可能发生的阻塞现象的假设是正确的,如果有一个延迟的异步任务,事件循环是否可以在等待任务返回控制权的同时处理其他任务?
>或者这个假设是错误的,所以事件循环在延迟的异步任务完成之前不起作用?
在 async await 的情况下,我想知道 await 是否停止了 Event Loop。
解决方法
您可以将事件循环视为实际循环,例如:
let event_queue = [compiled_toplevel_code];
while (true) {
if (event_queue.length === 0) {
sleepUntilWokenUp();
}
if (event_queue.length > 0) {
let callback = event_queue.shift();
callback();
}
}
其中 sleepUntilWokenUp()
是一个特殊的函数,它会挂起当前线程,直到另一个线程发送一些信号来唤醒它。异步操作(如文件系统或网络访问)由此类其他线程处理。当他们有一个回调准备好执行时,他们会将它排入队列,然后发送适当的唤醒信号。
您可以想象 setImmediate(callback)
被实现为 event_queue.push(callback)
。
从事件循环到回调的“转移控制”仅仅意味着调用回调; “返回控制”到事件循环只是意味着回调函数返回。
长时间运行的“异步”任务总是分解成在主线程上运行的片段,安排一些要完成的工作(通常在另一个线程上),然后返回。一旦请求的任务在后台完成,它们相应的回调就会被排队。即使使用 await
的“同步”调用也只是将函数分成两半的语法糖,这样前半部分运行完成,当等待的任务完成时,后半部分被推送到 event_queue
.
现实中的完整情况稍微复杂一些(在 Node 文档中有详细描述),不同种类的事物有几个不同的队列,但以上描述了总体思路。