Node.js事件驱动

   Node.Js是基于javascript语言,建构在google V8 engine以及Linux上的一个非阻塞事件驱动IO框架。这里主要不是介绍nodejs具体应用代码,而是想介绍一下事件驱动编程。

  Node.js事件驱动实现概览

  虽然在ECMAScript的标准里并没有(也没有必要)明确规定“事件”,但是在浏览器中,事件作为一个极为重要的机制,给予JavaScript响应用户操作与DOM变化的能力;在Node.js中,异步事件驱动模型则是其高并发能力的基础。

  学习JavaScript也需要了解它的运行平台,为了更好的理解JavaScript的事件模型,我打算从Node及浏览器引擎源码入手,分析其底层实现,并将我的分析整理为一系列博文;一方面作为笔记,另一方面也希望能与大家交流,分析和理解有疏漏偏颇之处,还望各位斧正。

  简述事件驱动模型

  解释JavaScript事件模型本身的好文章已经很多了,可以说这已经是一个说烂了的话题,这里我只简单写一下,并且提供一些好文章的链接。

  程序如何响应事件

  我们的程序响应外部的事件有如下两种方式:

  中断

  操作系统处理键盘等硬件输入就是通过中断来进行的,这个方式的好处是即使没有多线程,我们也可以放心地执行我们的代码,CPU收到中断信号之后自动地转去执行相应的中断处理程序,处理完成后会恢复原来的代码的执行环境继续执行。这种方式需要硬件的支持,一般来说都会被操作系统封装起来。

  轮询

  循环检测是否有事件发生,如果有就去执行相应的处理程序。这在底层和上层的开发中都有应用。

  Windows窗口程序就需要在主线程中写下如下代码,通常称做消息循环:

  ?

1
2
3
4
5
6

MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

  消息循环不断检测是否有消息(用户的UI操作、系统消息等)出现,有的话就分发消息,调用相应的回调函数进行处理。

  轮询方式的一个缺点就是:如果在主线程的消息循环里进行耗时操作,程序就无法及时响应新的消息。这在JavaScript中表现明显,以后还会提到这一点,并探讨其解决方案。

  然而JavaScript中并没有类似消息循环代码,我们只是简单地注册事件,然后等待被调用。这是因为浏览器、Node作为执行平台,已经将event loop实现了,JavaScript代码不需要介入到这个过程中,只需要作为被调用者安静地等待即可。

  Node中的event loop

  通过Node源码看event loop的实现

  Node采用V8作为JavaScript的执行引擎,同时使用libuv实现事件驱动式异步I/O。其事件循环就是采用了libuv的默认事件循环。

  在src/node.cc中,

  ?

1
2
3
4
5
6
7
8

Environment* env = CreateEnvironment(
node_isolate,
uv_default_loop(),
context,
argc,
argv,
exec_argc,
exec_argv);

  这段代码建立了一个node执行环境,可以看到第三行的uv_default_loop(),这是libuv库中的一个函数,它会初始化uv库本身以及其中的default_loop_struct,并返回一个指向它的指针default_loop_ptr。

  之后,Node会载入执行环境并完成一些设置操作,然后启动event loop:

  ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

bool more;
do {
more = uv_run(env->event_loop(), UV_RUN_ONCE);
if (more == false) {
EmitBeforeExit(env);
// Emit `beforeExit` if the loop became alive either after emitting
// event, or after running some callbacks.
more = uv_loop_alive(env->event_loop());
if (uv_run(env->event_loop(), UV_RUN_NOWAIT) != 0)
more = true;
}
} while (more == true);
code = EmitExit(env);
RunAtExit(env);
...

  more用来标识是否进行下一轮循环。

  env->event_loop()会返回之前保存在env中的default_loop_ptr,uv_run函数将以指定的UV_RUN_ONCE模式启动libuv的event loop。在这种模式下,uv_run会至少处理一个事件:这意味着,如果当前事件队列中没有需要处理的I/O事件,uv_run会阻塞住,直到有I/O事件需要处理,或者下一个定时器时间到。如果当前没有I/O事件也没有定时器事件,则uv_run返回false。

  接下来Node会根据more的情况决定下一步操作:

  如果more为true,则继续运行下一轮loop。

  如果more为false,说明已经没有等待处理的事件了,EmitBeforeExit(env);触发进程的'beforeExit'事件,检查并处理相应的处理函数,完成后直接跳出循环。

  最后触发'exit'事件,执行相应的回调函数,Node运行结束,后面会进行一些资源释放操作。

  在libuv中,定时器事件是直接在event loop中处理的,而I/O事件则分为两类:

  Network I/O是使用系统提供的非阻塞式I/O解决方案,例如在Linux上使用epoll,windows上使用IOCP。

  文件操作和DNS操作没有(很好的)系统解决方案,因此libuv自建了线程池,在其中进行阻塞式I/O。

  另外我们也可以将自定义的函数抛到线程池中运行,在运行结束后主线程会执行相应的回调函数,不过Node并没有将这一项功能加入到JavaScript中,也就是说只用原生Node是无法在JavaScript中开启新的线程进行并行执行的。

  以上所述就是本文的全部内容了,希望大家能够喜欢。

时间: 2024-12-01 17:19:31

Node.js事件驱动的相关文章

Node.js事件驱动模型

一.传统线程网络模型        在了解Node.js事件驱动模型之前,我们先了解一下传统的线程网络模型,请求进入web服务器(IIS.Apache)之后,会在线程池中分配一个线程来线性同步完成请求处理,直到请求处理完成并发出响应,结束之后线程池回收. 这就会就会带来以下几个问题 : 1.由于线程池中线程个数有限,对于频繁请求时,就会出现等待,严重的甚至会把服务器挂掉 2.对于高并发的时候,为了防止出现脏数据就会使用锁来解决,一些I/O事务可能消耗很长得时间,这样就会出现一些线程等待,效率低下

Node.js事件驱动_node.js

Node.js事件驱动实现概览 虽然在ECMAScript的标准里并没有(也没有必要)明确规定"事件",但是在浏览器中,事件作为一个极为重要的机制,给予JavaScript响应用户操作与DOM变化的能力:在Node.js中,异步事件驱动模型则是其高并发能力的基础. 学习JavaScript也需要了解它的运行平台,为了更好的理解JavaScript的事件模型,我打算从Node及浏览器引擎源码入手,分析其底层实现,并将我的分析整理为一系列博文:一方面作为笔记,另一方面也希望能与大家交流,分

快速掌握Node.js事件驱动模型_node.js

一.传统线程网络模型 在了解Node.js事件驱动模型之前,我们先了解一下传统的线程网络模型,请求进入web服务器(IIS.Apache)之后,会在线程池中分配一个线程来线性同步完成请求处理,直到请求处理完成并发出响应,结束之后线程池回收. 这就会就会带来以下几个问题 : 1.由于线程池中线程个数有限,对于频繁请求时,就会出现等待,严重的甚至会把服务器挂掉 2.对于高并发的时候,为了防止出现脏数据就会使用锁来解决,一些I/O事务可能消耗很长得时间,这样就会出现一些线程等待,效率低下 二.事件驱动

[译]理解Node.js事件驱动机制

学习 Node.js 一定要理解的内容之一,文中主要涉及到了 EventEmitter 的使用和一些异步情况的处理,比较偏基础,值得一读. 大多数 Node.js 对象都依赖了 EventEmitter 模块来监听和响应事件,比如我们常用的 HTTP requests, responses, 以及 streams. const EventEmitter = require('events');  事件驱动机制的最简单形式,是在 Node.js 中十分流行的回调函数,例如 fs.readFile.

浅谈 Node.js 和 PHP 进程管理

所周知,PHP 占据了服务端编程语言的半壁江山,正如汪峰在音乐圈的地位一般.随着 Node.js 逐渐走上服务端编程的舞台,关于 PHP 和 Node.js 孰优孰劣的争论也不曾间断. 垄断性的市场份额足以佐证 PHP 的优秀.并且 HHVM 虚拟机.PHP 7 的革新,也给 PHP 带来了跨越式的性能突破.然而,当我们为语言层面的性能差异喋喋不休时,却往往忽略了 Web 模型在性能表现中的权重. 从 CGI 到 FastCGI 早期的 Web 服务,是基于传统的 CGI 协议实现的.每个发送到

ReactPHP,PHP版的Node.js

前言 前段时间csdn找我约稿.一直忙于项目,也没来及写.十一的时候,学习了下ReactPHP.把了解的一些东西整理成文.难免有疏漏,如发现请指正.原文已经发布到csdn.网址 http://www.csdn.net/article/2015-10-12/2825887 从名字说起 虽然ReactPHP项目已经发展了有4年之久,但是对于其称呼显得有点混乱.在开源中国为其建立的项目主页上,其被命名为React,或者node.PHP.国外的一些的博客谈及这个项目时,多数使用的是ReactPHP.到底

Node.js 学习笔记之简介、安装及配置

 本文是Node.js学习笔记系列文章的第一篇,主要给大家讲解的是在Windows和Linux上安装Node.js的方法.软件安装版本以0.12.0为例.希望大家能够喜欢.     简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台. Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好. 谁适合阅

Node.js软肋之CPU密集型任务

Node.js在官网上是这样定义的:"一个搭建在Chrome JavaScript运行时上的平台,用于构建高速.可伸缩的网络程序.Node.js采用的事件驱动.非阻塞I/O模型使它既轻量又高效,是构建运行在分布式设备上的数据密集型实时程序的完美选择."Web站点早已不仅限于内容的呈现,很多交互性和协作型环境也逐渐被搬到了网站上,而且这种需求还在不断地增长.这就是所谓的数据密集型实时(data-intensive real-time)应用程序,比如在线协作的白板,多人在线游戏等,这种we

使用Node.js配合Nginx实现高负载网络

  这篇文章主要介绍了使用Node.js配合Nginx实现高负载网络,Node的异步加上Nginx的反向代理在性能上实在是给力!需要的朋友可以参考下 在搭建高吞吐量web应用这个议题上,NginX和Node.js可谓是天生一对.他们都是基于事件驱动模型而设计,可以轻易突破Apache等传统web服务器的C10K瓶颈.预设的配置已经可以获得很高的并发,不过,要是大家想在廉价硬件上做到每秒数千以上的请求,还是有一些工作要做的. 这篇文章假定读者们使用NginX的HttpProxyModule来为上游