事件轮询(引用)

事件轮询是node的核心内容。一个系统(或者说一个程序)中必须至少包含一个大的循环结构(我称之为“泵”),它是维持系统持续运行的前提。nodejs中一样包含这样的结构,我们叫它“事件轮询”,它存在于主线程中,负责不停地调用开发者编写的代码。我们可以查看nodejs官方网站上对nodejs的说明:

Node is similar in design to and influenced by systems like Ruby's Event Machine or Python's Twisted. Node takes the event model a bit further, it presents the event loop as a language construct instead of as a library. In other systems there is always a blocking call to start the event-loop. Typically one defines behavior through callbacks at the beginning of a script and at the end starts a server through a blocking call like EventMachine::run(). In Node there is no such start-the-event-loop call. Node simply enters the event loop after executing the input script. Node exits the event loop when there are no more callbacks to perform. This behavior is like browser JavaScript -— the event loop is hidden from the user.

node在设计上类似于Ruby的Event Machine或Python的Twisted等系统,并受其影响。 node进一步采用事件模型,它将事件循环呈现为语言构造而不是库。 在其他系统中,总是有一个阻塞调用来启动事件循环。 通常,通过在脚本开头的回调定义行为,最后通过阻塞调用(如EventMachine :: run())启动服务器。 在Node中没有这样的启动 - 事件循环调用。 node在执行输入脚本后简单地进入事件循环。 当没有更多的回调要执行时,Node退出事件循环。 这种行为就像浏览器JavaScript - 事件循环对用户是隐藏的。

从中可以看出,其他语言当存在阻塞的时候才会调用event loop,而node会在输入脚本的时候就会进入事件循环。

我们可以看到,在nodejs中这个“循环”结构对开发者来讲是不可见的。(借用别人的图)

如上图所示,每个异步函数执行结束后,都会在事件队列中追加一个事件(同时保存一些必要参数)(这里面有如下内容1.node怎么判断这个异步程序执行完了 2.执行完后,是怎么放入到事件队列中的)。事件轮询下一次循环便可取出事件,然后会调用(这个事件对应的)异步方法对应的回调函数(参数,Q:怎么区分这个回调函数是属于这个事件(或者说是这个异步方法的?))。这样一来,nodejs便能保证开发者编写的每行代码(每个回调)均在主线程中执行。
1.异步程序的过程中,如果出错,则该异步结果会直接进入到事件队列中,传入的参数将会是回调函数的第一个参数。

2.如果开发者在回调函数中调用了阻塞方法,那么整个事件轮询就会阻塞,事件队列中的事件得不到及时处理,node就会卡死,随后就会崩溃。正因为这样,nodejs中的一些库方法均是异步的,也提倡用户调用异步方法。如果在回调函数中产生错误,则从  调用对应的异步函数   ->  取事件 造成阻塞,node就会崩溃。

其实看到这里的时候,如果有对Windows编程(尤其对Windows界面编程)比较了解的读者可能已经联想到了Windows消息循环。

没错,nodejs中的事件轮询原理跟Windows消息循环的原理类似。开发者编写的代码均运行在主线程中,如果你编写了阻塞代码,在Windows桌面程序中,由于消息得不到及时处理,界面就会卡死。

咱们再来看一下下面的nodejs代码:

var fs = require('fs');
fs.readFile('hello.txt', function (err, data) {  //异步读取文件
  console.log("read file end");
});
while(1){
    console.log("call readFile over");
}

如上,虽然我们使用异步方法读取文件,但是文件读取完毕后“read file end”永远不会输出,也就是说readFile方法的回调函数不会执行。原因很简单,因为后面的主进程的while循环一直没退出,导致下一次事件轮询不能开始,所以回调函数不能执行(包括其他所有回调)。事实再次证明,开发者编写的所有代码均只能运行在同一线程之中(姑且称之为主线程吧)。

关于异步方法

所谓异步方法,就是调用该方法不会阻塞调用线程,哪怕方法内部要进行耗时操作。你可以理解为方法内部单独开辟了一个新线程去处理任务(主进程一直进行工作,而开的新线程处理异步的工作),而调用异步方法仅仅是开启这个新线程。下面的代码模拟一个异步方法的内部结构(仅仅是模拟,不代表实际):

在.NET中,每个异步方法的回调函数均在另外一个线程中执行(非调用线程),而在nodejs中,每个异步方法的回调函数仍然还在调用线程上(可以理解为主线程)执行。至于为什么,大家可以看一下前面讲事件轮询的部分,nodejs中每个回调函数均由主线程中的事件轮询来调用。这样才能保证在nodejs中,开发者编写的任何代码均在同一个线程中运行(所谓的单线程)。http://www.cnblogs.com/xiaozhi_5638/p/4268223.html

消息循环就应该是"泵",消息队列就应该是"数据容器",Windows消息就应该是"数据",而窗口过程就应该是"处理者",那么整个结构应该

既然框架能够保证最终应用程序的持续正常工作,按照本章前面的结论,那说明框架内部必然有一种结构能够重复性处理问题,这种结构就是"泵",泵的"持续性"和"动力性"特性完全满足框架的需求。如果需要将这种抽象关系图形化显示出来,见下图10-18:

既然我们最终的应用程序是在框架的基础之上扩展出来的,这说明应用程序的主要运行逻辑、主要的流程控制均是由框架决定的,框架控制应用程序的启动、决定主要的流程转向,负责调用框架使用者编写的"扩展代码",总之,框架能够保证最终应用程序的持续正常工作。

这些 扩展代码 就是经常说到的 Hook函数(或者一些属性),然后模板的其他的内容就是写死的。只有Hook是固定的。

node.js事件轮询(1)的更多相关文章

  1. 【译】理解node.js事件轮询

    Node.js的第一个基本论点是I/O开销很大. 当前编程技术中等待I/O完成会浪费大量的时间.有几种方法可以处理这种性能上的影响: 同步:每次处理一个请求,依次处理.优点:简单:缺点:任何一个请求都 ...

  2. js事件轮询机制

    console.log(1) setTimeout(function(){ console.log(2) },0); console.log(3) 毫无疑问:运行结果是1 3 2 也就是说:setTi ...

  3. 理解Node.js的事件轮询

    前言 总括 : 原文地址:理解Node.js的事件轮询 Node小应用:Node-sample 智者阅读群书,亦阅历人生 正文 Node.js的两个基本概念 Node.js的第一个基本概念就是I/O操 ...

  4. Node.js的异步IO和事件轮询

     想象一下,以前我们在写程序时, 如果程序在I/O上阻塞了,当有更多请求过来时,服务器会怎么处理呢?在这种情景中通常会用多线程的方式.一种常见的实现是给每个连接分配一个线程,并为那些连接设置一个线程池 ...

  5. Node.js的事件轮询Event Loop原理

    Node.js的事件轮询Event Loop原理解释 事件轮询主要是针对事件队列进行轮询,事件生产者将事件排队放入队列中,队列另外一端有一个线程称为事件消费者会不断查询队列中是否有事件,如果有事件,就 ...

  6. node.js中的事件轮询Event Loop

    任务队列/事件队列 "任务队列"是一个事件的队列,IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈" ...

  7. 对Node.JS的事件轮询(Event Loop)的理解

    title: Node.JS的事件轮询(event loop)的理解 categories: 理解 tags: Node JS 机制 当我们知道I/O操作和创建新线程的开销是巨大的! 网站延迟的开销 ...

  8. 浅析libuv源码-node事件轮询解析(4)

    这篇应该能结,简图如下. 上一篇讲到了uv__work_submit方法,接着写了. void uv__work_submit(uv_loop_t* loop, struct uv__work* w, ...

  9. 浅析libuv源码-node事件轮询解析(2)

    上一篇讲了轮询的边角料,这篇进入正题.(竟然真有人看我博客,上两个图给你们整理下思路) 这是轮询总流程图. 下图为本节内容简图. Poll for I/O The loop blocks for I/ ...

随机推荐

  1. Socket通信原理探讨(C++为例)

    一.网络中进程之间如何通信? 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 1.消息传递(管道.FIFO.消息队列) 2.同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 3 ...

  2. mysql远程连接问题

    问题:在服务器里面新安装一个MYSQL数据库,结果在远程电脑连接不上,并提示“服务器连接错误Host 'XXX' is not allowed to connect to this MySQL ser ...

  3. MySQL 相关

    Innodb引擎 Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别.该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统. 但是该引擎不支持FULLT ...

  4. iOS NSOperation 封装 通知实现界面更新

    #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface MYOperation : NSOpe ...

  5. Daily Scrum Meeting ——NinthDay

    一.Daily Scrum Meeting照片 二.Burndown Chart 三.项目进展 1.用户管理 2.下拉框与界面的整合 四.问题困难 黄志明(PM):Android Studio自带的S ...

  6. [工作中的设计模式]迭代子模式Iterator

    一.模式解析 迭代子模式又叫游标(Cursor)模式,是对象的行为模式.迭代子模式可以顺序地访问一个聚集中的元素而不必暴露聚集的内部表象 1.迭代子模式一般用于对集合框架的访问,常用的集合框架为lis ...

  7. RUDP之三 —— Virtual Connection over UDP

    原文链接 原文:http://gafferongames.com/networking-for-game-programmers/virtual-connection-over-udp/ Introd ...

  8. Sharepoint + Office Infopart + Quick Apps for Sharepoint搭建无纸化工作平台

    项目背景: 某大型外企各分部通过互联网专线统一域环境,Exchange邮件系统,Sharepoint平台及依赖环境已经购买并搭建起来,Dell Quick app for Sharepoint已购卖并 ...

  9. data Binding

    在WEEX中,我们使用{{}}双括号来对数据进行绑定,一旦我们对数据进行了绑定,当数据发生改变时,模板中的内容也会发生相应的改变. 如果绑定的数据是一个对象,里面有很多的内容,我们可以使用  .   ...

  10. 通过PowerShell启用AADC的密码同步功能

    在AADC工具里面也可以启用. 下面这个是世纪互联工程师提供的Powershell脚本(我测试了下是可以的),其中,$adConnector和$aadConnector可以在AADC工具里面找到. $ ...