Node探秘之事件循环(1)--几个基本要素

前言

对于想要真正理解JavaScript工作机制的人,理解JS的事件循环(Event Loop)应当是首当其冲的绕不过的坎。因为事件驱动模型的设计和事件循环机制的实现,才使得js成为一门真正纯异步,使得回调函数十分普遍的编程语言,也是Node之所以被作为网络应用节点,用于高效处理并发I/O的原因。

当你真正理解了事件循环机制时,下面这样的一些问题相信你也会就了然了。

问题1


解释JavaScript事件模型本身的文章还是非常多的,并且不乏有不少出色的文章。本文将引用部分文章的图片,结合对Node源码的分析,逐步理出Node事件循环机制的实现原理。

因为在写本文时,主要参考的是朴灵老师写的《深入浅出nodejs》,写这本书时的node稳定版本为0.10.13,且早期版本的node源码较少,读起来较为容易理解,因此这里的代码分析主要是基于0.10.13来进行的。

事件循环

大家都知道,一般我们会讲JS是单线程的,Node在处理I/O的时候也是单线程的,好处就是没有线程的切换和数据共享的问题。但实际上,在系统底层,非阻塞的I/O解决方案,只有Network I/O部分,linux底层使用epoll,windows下使用IOCP。文件等操作则没有很好的系统解决方案,因此为了模拟实现非阻塞的I/O方案,Node在libuv层启用了一个线程池,用于调用系统的阻塞式I/O。

因此,实际上,node只是在应用层属于单线程,底层其实通过libuv维护了一个阻塞I/O调用的线程池。

JS之所以可以在执行异步操作时可以设置好callback函数之后,就继续执行后续代码,当异步操作执行完成时,又能够及时触发回调函数,获取异步结果。最关键的核心就在于事件循环。

在进程启动时,Node便会创建一个类似于while(true)的循环,每执行一次循环体的过程被称为tick,中文翻译应该意为“滴答”,就像时钟一样,每滴答一下,就表示过去了1s。这个tick也有点这个意思,每循环一次,都表示本次tick结束,下次tick开始。每个tick开始之初,都会检查是否有事件需要处理,如果有,就取出事件及关联的callbak函数,如果存在有关联的callback函数,就把事件的结果作为参数调用这个callback函数执行。如果不在有事件处理,就退出进程。


Tick流程图

那么在每个tick的过程中,如何判断是否有事件需要处理,先要引入一个概念,叫做“观察者”(watcher)。每一个事件循环都有一个或者多个观察者,判断是否有事件要处理的过程就是向这些观察者询问是否有需要处理的事件

Node的观察者有这样几种:

idle观察者:顾名思义,就是早已等在那里的观察者,以后会说到的process.nextTick就属于这类

I/O观察者:顾名思义,就是I/O相关观察者,也就是I/O的回调事件,如网络,文件,数据库I/O等

check观察者:顾名思义,就是需要检查的观察者,后面会说到的setTimeout/setInterval就属于这类

事件循环是一个典型的生产者/消费者模型。异步I/O,网络请求,setTimeout等都是典型的事件生产者,源源不断的为Node提供不同类型的事件,这些事件被传到对应的观察者那里,事件循环在每次tick时则从观察者那里取出事件并处理。

我们现在知道,JavaScript的异步I/O调用过程中,回调函数并不由我们开发者调用,事实上,在JavaScript发起调用到内核执行完I/O操作的过程中,存在一种中间产物,它叫做请求对象。这个请求对象会重新封装回调函数及参数,并做一些其他的处理。这个请求对象,会在异步事件完成时被调用,取出回调函数和参数,并传入执行结果进行回调。这个请求对象,在下一篇介绍setTimeout等的文章中会举例。

组装好请求对象,送入I/O线程池等待执行,实际上只是完成了异步I/O的第一步;第二步则是异步I/O被线程池处理结束后的回调,也就是执行回调

因为事件循环的逻辑就是这样,这里就不手工再重新绘制一张异步I/O流程图,直接把朴老师书里面的图贴上来给大家看。

应该说,事件循环、观察者、请求对象、I/O线程池,这四者共同组成了Node异步I/O模型的基本要素。

源码分析

下面我给出0.10.13中关于事件循环的源码分析结果图对上述分析给予说明


总结


根据源码分析图,可以请求出得出这样几个结论:

1、每次tick都会检查所有完成的回调事件,并一一执行回调函数。

2、跑完当前执行环境下能跑完的代码。每一个事件消息都被运行直到完成为止,在此之前,任何其他事件都不会被处理。这和C等一些语言不通,它们可能在一个线程里面,函数跑着跑着突然停下来,然后其他线程又跑起来了。JS这种机制的一个典型的坏处,就是当某个事件处理耗时过长时,后面的事件处理都会被延后,直到这个事件处理结束,在浏览器环境中运行时,可能会出现某个脚本运行时间过长,页面无响应的提示。Node环境则可能出现大量用户请求被挂起,不能及时响应的情况。

3、不同类型的观察者,处理的优先级不同,idle观察者最先,I/O观察者其次,check观察者最后。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 155,457评论 4 357
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 65,943评论 1 285
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,327评论 0 236
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,307评论 0 201
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,630评论 3 283
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,114评论 1 202
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,514评论 2 305
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,227评论 0 193
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,859评论 1 234
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,186评论 2 238
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,741评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,087评论 2 248
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,614评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,926评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,630评论 0 190
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,117评论 2 261
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,076评论 2 257

推荐阅读更多精彩内容