刚学node.js不久,了解了一下事件循环的机制,有几个小白问题想问一下大家: 我知道事件循环有六个阶段,每个阶段都是处理一个队列中的所有回调,处理完成后或阻塞或进入下一阶段。 1.那启动时候执行的代码属于哪一个阶段的处理呢,还是说是另外的阶段处理? 2.事件循环会在poll阶段发生阻塞(callback队列为空,且没有通过setImmediate()设置callback),那这个阻塞是如何被唤醒的,比如通过setTimeOut的时间到了,如何唤醒阻塞然后执行到Timer阶段。 暂时就是这两个问题,希望大佬们指点一下。
个人理解: 1.第一阶段运行 2.eventloop一直在循环检查,直到 timers 在预设时间到了就会立即执行。 参考文章:https://www.jianshu.com/p/deedcbf68880
@ddzyan 1.是说在timers阶段执行的吗,我觉得启动执行的这段执行的代码应该也是会封装成一个callback扔到某个阶段的队列里执行吧,不知道在哪里怎么能看到这些内容。 2.我理解eventloop就是一个主线程,那如果主线程已经阻塞了,相当于线程进入了一个状态,那在这个状态之下它自己就不会再继续执行了, 必须得有另一个线程来唤醒它。所以我猜测一种可能就是,这里说的阻塞其实并不是主线程进入了某种状态,只是说他被标记成停在poll阶段,而它本身还是在做循环检查判断的逻辑。 3.针对这两点,我还多了个疑问,就是你们是怎么看node的源码的,看看源码是不是就能确认了。
还有个问题就是我们怎么写一个让其他线程执行的任务呢,其实就是说node如何知道你的这个任务是需要其他线程去执行的,然后完了再回调,比如fs.readFile,是怎么调用的导致它由其他线程去完成读取
@ddzyan 刚又看了以下官方文档,大概理解poll阶段的阻塞到底是怎么回事了,简单说就是进入poll阶段后如果没有设置timers的callback,当queue里的callback执行完后就会进入阻塞状态(没有设置setImmediate的callback),这种情况下就真的阻塞等待新的callback了,如果有I/O事件触发的时候,会唤醒主线程继续执行。而如果poll阶段callback全部执行完后发现有设置timers,它就不会进入阻塞状态,会一直不断检查直到某个timers的callback需要回调了,然后循环到那个阶段进行执行。 应该是这样吧。
启动时候执行的代码 执行的代码你指的是同步的javascript的代码?事件循环的六个阶段触发的只是在异步的时候传入callback哦,初始的javascript代码不在这六个阶段里;最近总结了一篇:https://juejin.im/post/5d21f7e9e51d455071250b81
@pangjiawei19 源码是C和C++的,可以去看下
@pangjiawei19 准确的说,主线程执行的第一步是执行所有js代码,遇到堵塞在加入到event loop中。根据 event loop 轮询机制发现已经完成的事件,则通知主线程进行处理。
问题1:执行完同步代码才启动的eventloop 问题2:poll阶段其实是调用了linux的epoll,这个支持传一个时间参数吧,等多久等不到也会返回的样子
@FantasyGao 大佬看了你的文章,写的很不错的,就这个同步代码执行的问题,我还是有两个疑问: 1.这段启动时候执行的同步代码,不在六个阶段里,那是不是说执行完这块以后,主线程就开始在事件循环里轮询了? 2.如果我的代码里没有可能产生异步io然后进行回调的逻辑,那这个事件循环会被初始化吗?我理解如果初始化了事件循环,主线程就会阻塞到poll阶段了,那我程序直接结束说明没有初始化事件循环,对吗?
1.启动阶段main() -> node::Start(argc, argv) -> NodeMainInstance::Run() -> CreateMainEnvironment() -> RunBootstrapping() 执行完internal/bootstrap的node.js启动文件后,Module.runMain执行 process.argv[1]
2.之后进入do { uv_run(env->event_loop(), UV_RUN_DEFAULT)} while (more == true && !env->is_stopping());
timeout = uv_backend_timeout(loop); 计算距离最近一个定时器的时间差
uv_io_poll(loop, timeout);
@pangjiawei19 事件循环和主线程没有关系
@ddzyan 额,那事件循环执行的逻辑是哪个线程在跑呢?