该书对我学习nodejs帮助不少,感谢朴灵。 但读到关于事件循环章节就看不下去了,因为理解不到其对事件循环原理的解释。 他提到这么一段,大意是:在node进程启动时,node就创建一个while循环,检查观测者(事件队列)中是否有事件存在,如果存在就取出事件,执行回调函数后继续循环,如果不存事件就退出进程。 他举了一个生动的例子:餐馆的厨师获取前台妹子收到的客户订单,之后根据订单做菜。做完一单取下一单,如此往复。如果没有订单就下班打烊和妹子约去了。
我疑问就来了,餐馆的老板朴灵对员工这么好吗?是不是厨师早上来上班,如果还没有客人来吃饭,就可以马上下班了,之后来的客人就只能吃闭门羹了?
同样的问题,如果有一个很耗时的IO操作,IO还未完成,还未把事件给到观测者,则在while循环中,还没有在观测者中取得事件。按朴灵的说法,该循环就要退出进程了。那么当这个IO完成后,这个事件回调就不会执行了?
再问个问题,node进程启动,是不是指在CMD执行 node app.js之后?这时就产生循环了?
下面是我对循环的理解,请大神指点纠正,谢谢! 1、假设我们在一个web应用中请求一个链接,执行了一个js文件,js文件代码按顺序同步执行,遇到IO操作,node api把这些异步操作扔给线程池处理,并在队列中记录这个IO操作,继续向下执行,记录所有的IO操作到队列中; 2、执行了js文件的最后一行后,才生成一个事件循环,循环检查第一步中记录了IO操作的队列,检查队列中的记录是否有对应的事件,如果有就取出事件执行回调,如果没有就继续循环下去; 3、继续循环检查队列中的记录,直到所有记录都产生了事件,并执行回调。这时才结束循环退出进程; 4、如果上面的循环还未结束,我们又请求了一个链接,这个请求的js程序就等待上面的循环完成才开始执行(因为是单线程web服务,所有请求都是在同一个线程中,循环也是在相同的线程中运行,所以要等待)。这个js程序也像2、3步一样的过程,在程序执行到最后一行之后,又生成一个循环,检查队列记录,执行事件。
by lhz
事件循环机制不止node有,你可以看安卓的loop epoll
来自酷炫的 CNodeMD
io 操作没完成怎么能说 loop 中就没有事件了?io 事件不还在么,当然不会退出了。
来自酷炫的 CNodeMD
我只能说用现实例子来类比复杂的 eventloop 过程是有点强人所难,因为意思大概能到,但实际上的细节差别可能非常大。
这个例子中。并不是说没客人来吃饭,就可以下班了。关键还要看前台妹纸,前台妹纸没下班,厨师能下班?
以定时器为例,当(第一次)执行 setTimeout 的时候,会建立 timer watcher, timer watcher 持有这个 handler。 eventloop 执行的过程中,会询问 timer watcher, 是否有 event,如果有,处理 event,看情况决定是否取消持有 handler(setInterval 会多次产生 event)。
解除 watcher 对 handler 的持有关系有两种,一种是自然执行结束,另一种是通过 unref。
当所有 watcher 都不再持有 handler 了,eventloop 就会退出。
我正在写作第二版的《深浅》,将会更少从感性上去描述这个过程。
主文件执行后,Node 会主动调用一次 process.nextTick() 来进入 eventloop。
@JacksonTian 期待第二版,必买
你就这样想吧,非回调函数全部执行了(如果这时遇到回调函数就会塞到一个队列里面,fs的回调除外), 再用while循环执行回调函数的那个队列(期间可能回调函数会不断生成) 。 这个队列没代码要执行了,while就结束了,接下来就退出进程了。 虽然专业术语可能有偏差和实际运行上有些遗漏,但基本实现你可以这样理解。 而且我这个大白话文版应该很好理解了 哈;)
接下来,是问答环节: Q:你纳闷这样不阻塞吗? A:当然会阻塞,够快不就好了,这也是node不适合CPU密集运算的原因。 Q:读写文件怎么办,这不会阻塞吗? A:所以fs的回调他是使用线程池啊。 Q:会阻塞干嘛还用队列? A:这其实是保证了CPU不会在等待的时候浪费
@JacksonTian 解析后大概明白了。 @zy445566 没错,你的理解和我本身的理解是一样的。我纳闷阻塞是因为书中提到while是在node进程启动的时候生成,我就想你这么早就while,下面的代码有机会执行吗?JacksonTian 也回复了,是在主文件执行后才进入eventloop,执行event。待所有event执行完才退出。
哈哈,作者本人来了
@ianchn 这才是一个负责任的作者。力挺啊。
@JacksonTian 什么时候出二呀
我好像觉得,你在用思考js的套路来思考node的搭建。。。但是,,单纯用js是写不出node来?(比如你考虑执行循环之后阻塞了,是否是在主文件加载完后再执行evenloop),个人觉得node的这种事件循环机制可以看作是另类的系统信号,,至于如何做到这个信号,和程序无关(nodejs代码)和系统有关(node本身),。。当然,我是彩笔,只是凑凑话题,具体以大神为准
我之前关于Node 网络异步IO的分析(参照了社区的文章进行分析): http://luoxia.me/code/2017/07/27/libuv%E7%BD%91%E7%BB%9CIO%E6%9C%BA%E5%88%B6/
实际上node执行的用户代码是在V8单独的线程执行,node主进程实际上在进行了一系列初始化后,进入了一个event loop,只有当没有任何handle和request的时候,循环才结束。
@lianghz 不用谢,我邀请的 😜
@JacksonTian 好奇啥时候出第二版,真的好想买一本
@JacksonTian 同样期待,必买啊!!!
哇,我刚看了这本书的时间循环,直接就过去了,为啥我就没有你这样的思考呢,怪不得自己这么菜(佩服lz看的挺仔细的,挺会思考的)? @JacksonTian 期待作者的第二版