Node.js的事件循环(事件循环)和线程池的详细方案

Node.js的事件循环(事件循环)和线程池的详细方案
事件循环(event loop)节点是其处理大并发和高吞吐能力的核心。这是最了不起的地方,Node.js基本上是理解为一个单一的线程并允许任何操作是在后台处理。本文将解释如何活动周期,你也能感觉到它的魔力。

事件驱动编程

为了理解事件周期,首先理解事件驱动的编程,它出现在1960。今天,事件驱动编程广泛应用于UI编程中。Javascript的主要用途之一是与DOM交互,所以使用基于事件的API是很自然的。

简单定义:事件驱动编程通过事件或状态的变化来控制应用程序,它通常由事件监控实现,一旦检测到事件(即状态改变),就会调用相应的回调函数。事实上,这是对Node.js的事件循环的基本原理。

如果你熟悉客户端Javascript开发,想想那些。*()方法,如element.onclick(),并结合DOM元素的迁移用户交互。这种工作方式允许将多个事件在一个单一的instance.node.js触发触发此模式通过EventEmitter(事件发生器),这样在服务器端socket和HTTP模块。一个或多个状态的变化可以从一个单一的实例触发。

另一个常见的模式是成功的成功和失败表示失败。有实现它现在常用的两种方法。第一是通过错误异常的回调,通常是作为回调函数的第一个参数传递。二是承诺的设计模式的使用,它已被添加到6。承诺模式使用jQuery的功能一样链写作方法,避免深幅回调函数的嵌套,如:

复制代码代码如下所示:

美元。getJSON( / getUser)。做(successhandler)失败(failhandler)。
大多数的FS(文件系统)模块采用来料异常的风格在后面的音。有些电话触发技术,如fs.readfile()额外的事件,但是API只是提醒用户表达的成功或失败的操作。这样一个API的选择是基于建筑考虑,而不是技术上的限制。

一个常见的误解是,事件生成器(事件发射器)在触发事件时也是自然异步的,但这是不正确的。

复制代码代码如下所示:

函数的MyEmitter(){

eventemitter.call(本);

}

util.inherits(myemitter,EventEmitter);

myemitter.prototype.dostuff =功能doStuff(){

console.log(以前)

Emitter.emit()

console.log(' ')}

};

VAR我=新MyEmitter();

Me.on(函数(){(){

console.log('emit开除);

});

Me.doStuff();

输出:
发射/发射
如果emitter.emit是异步的,输出应
发射/发射
EventEmitter往往是非常异步的,因为它往往是用来通知需要异步完成的操作,但EventEmitter API本身是完全同步的,听者内功能可以异步执行,但注意所有的听力功能将在添加顺序执行。

机制概述和线程池

节点本身依赖于多个图书馆。其中一个是libuv,对异步事件队列的魔法和图书馆的执行。

节点尽可能使用尽可能多的操作系统内核来实现现有的功能,比如生成响应请求(请求)、向前连接(连接)和委托给系统处理,例如,传入连接由操作系统管理,直到节点可以处理它们为止。

你可能听说过节点都有一个线程池,你可能想知道为什么一个线程池,如果节点将以任务过程中所需要的。这是因为在内核中,不是所有的任务都是异步执行的。在这种情况下,Node.js必须能够锁定的线程一段时间,它可以继续执行事件循环无阻。

下面是一个简单的示例图,以显示他内部的运行机制:
┌—————┐

带有/定时器/

-

屈-苯乙烯-┐

我们进行回调/悬而未决

-:-┌——┐

屈-芪┐ / /输入:

我们执行轮询连接/人。

-。

屈-芪┐--

人-人,setimmediate

---- ----

理解事件循环的内部运行机制有一定的困难:

所有的回调函数是由process.nexttick(),一个阶段的事件循环结束之前(例如,一个定时器)和下一个阶段之前,这将避免潜在的递归调用process.nexttick()和无限循环。

等待回调(等待回调)在回调队列,不会被任何其他事件循环处理回调(例如,通过FS。写)。

事件发射器和事件循环

通过创建EventEmitter,与事件循环的相互作用可以简化。这是一个普遍的封装,使它为你创建的基于事件的API更容易。这两个相互作用往往使开发商感到困惑。

下面的示例表明,被遗忘的事件是同步触发的,并可能导致事件丢失。

复制代码代码如下所示:

/ /后v0.10,不再需要('eventsEventEmitter)。

Var EventEmitter =需要('events);

VaR工具=需要('util);

功能喜欢这样事(){

eventemitter.call(本);

DoFirstThing();

This.emit('thing1);

}

util.inherits(喜欢这样事,EventEmitter);

VaR MT =新喜欢这样事();

Mt.on('thing1,功能onthing1()){

/对不起,这件事永远不会发生。

});
的above'thing1'event不会被MyThing(),因为喜欢这样事()必须被实例化听事件。下面是一个简单的解决方案,不需要添加任何额外的关闭:

复制代码代码如下所示:

Var EventEmitter =需要('events);

VaR工具=需要('util);

功能喜欢这样事(){

eventemitter.call(本);

DoFirstThing();

setimmediate(emitthing1,这个);

}

util.inherits(喜欢这样事,EventEmitter);

功能emitthing1(自我){

Self.emit('thing1);

}

VaR MT =新喜欢这样事();

Mt.on('thing1,功能onthing1()){

实现

});
下面的方案也可以工作,但会失去一些性能:

复制代码代码如下所示:

功能喜欢这样事(){

eventemitter.call(本);

DoFirstThing();

功能#绑定 / /(使用)的性能损失

setimmediate(this.emit.bind(这'thing1 '));

}

util.inherits(喜欢这样事,EventEmitter);
另一个问题是引发的错误(异常),找出应用程序中的问题是困难的,但它几乎是不可能的调试没有调用堆栈(注* e.stack)。在远程异步请求的错误调用堆栈将丢失。有两个可行的解决方案:同步触发或保证误差和其他重要的信息。以下的例子证明这两个解决方案:

复制代码代码如下所示:

mything.prototype.foo =函数foo(){

这将是错误/异步触发器。

无功二= dofirstthing();

如果(呃){

当被触发时,您需要创建一个新站点来保留调用堆栈信息错误。

setimmediate(emiterror,这新的错误(坏东西));

返回;

}

立即触发错误(同步)

无功二= dosecondthing();

如果(呃){

This.emit(错误,坏东西);

返回;

}

}
法官审时度势 u3002when误差引起的,它可以立即处理。或者,它可能是微不足道的,易于处理,或异常,将返工后。此外,通过构造函数传递错误,这不是个好主意,因为构造的对象情况有可能是不完整的。仅仅将错误直接的情况是个例外。

结语

本文讨论了事件循环的内部运行机制和技术细节,都是深思熟虑的。另一篇文章将讨论事件循环和系统内核和显示NodeJS的异步操作的魔法之间的相互作用。

tag:事件循环线程池方案详细电脑软件

相关内容