Node.js 循环
事件循环的流程
- 任务进入事件循环队列。
- 事件循环按照阶段顺序进行处理,每个阶段有自己的回调队列。
- 事件循环会在
poll阶段等待新的事件到达,如果没有事件,会检查其他阶段的回调。 - 如果
setImmediate()和setTimeout()都存在,setImmediate()在check阶段先执行,而setTimeout()在timers阶段执行。
实例
setTimeout(() => {
console.log('Timeout callback');
}, 0);
setImmediate(() => {
console.log('Immediate callback');
});
console.log('Main thread execution');
输出顺序:
Main thread execution先打印。setImmediate()和setTimeout()的执行顺序取决于当前事件循环的状态,一般setImmediate()会先执行。
宏任务与微任务
- 宏任务:
setTimeout、setInterval、setImmediate、I/O 操作等。 - 微任务:
process.nextTick、Promise.then。
执行顺序:微任务优先级高于宏任务,会在当前阶段的回调结束后立即执行。
实例
setTimeout(() => {
console.log('Timeout callback');
}, 0);
Promise.resolve().then(() => {
console.log('Promise callback');
});
console.log('Main thread execution');
执行输出结果:
Main thread execution Promise callback Timeout callback
process.nextTick()
process.nextTick() 会在当前操作结束后、下一个阶段开始前执行微任务,优先级高于 Promise。
实例
process.nextTick(() => {
console.log('Next tick callback');
});
console.log('Main thread execution');
输出:
Main thread execution Next tick callback
事件驱动程序
在 Node.js 中,事件驱动编程主要通过 EventEmitter 类来实现。
EventEmitter 是一个内置类,位于 events 模块中,通过继承 EventEmitter,你可以创建自己的事件发射器,并注册和触发事件。
通过这种机制,Node.js 可以高效地处理异步任务,即使在单线程的环境下也能实现并发处理。

整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。
实例
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件触发');
});
setTimeout(function() {
event.emit('some_event');
}, 1000);
运行这段代码,1 秒后控制台输出了 some_event 事件触发。其原理是 event 对象注册了事件 some_event 的一个监听器,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 some_event,此时会调用some_event 的监听器。
执行结果如下:
$ node event.js some_event 事件触发
EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter 支持 若干个事件监听器。
当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
让我们以下面的例子解释这个过程:
实例
//event.js 文件
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
});
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
});
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数');
执行以上代码,运行的结果如下:
$ node event.js listener1 arg1 参数 arg2 参数 listener2 arg1 参数 arg2 参数
以上例子中,emitter 为事件 someEvent 注册了两个事件监听器,然后触发了 someEvent 事件。
运行结果中可以看到两个事件监听器回调函数被先后调用。 这就是EventEmitter最简单的用法。
EventEmitter 提供了多个属性,如 on 和 emit。on 函数用于绑定事件函数,emit 属性用于触发一个事件。接下来我们来具体看下 EventEmitter 的属性介绍。
方法
| 序号 | 方法 & 描述 |
|---|---|
| 1 | addListener(event, listener) 为指定事件添加一个监听器到监听器数组的尾部。 |
| 2 | on(event, listener) 为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。
server.on('connection', function (stream) {
console.log('someone connected!');
});
|
| 3 | once(event, listener) 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。
server.once('connection', function (stream) {
console.log('Ah, we have our first user!');
});
|
| 4 | removeListener(event, listener)
移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。 它接受两个参数,第一个是事件名称,第二个是回调函数名称。
var callback = function(stream) {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
|
| 5 | removeAllListeners([event]) 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。 |
| 6 | setMaxListeners(n) 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于改变监听器的默认限制的数量。 |
| 7 | listeners(event) 返回指定事件的监听器数组。 |
| 8 | emit(event, [arg1], [arg2], [...]) 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。 |
Node.js 目前支持的字符编码包括:
-
ascii - 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的。
-
utf8 - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。
-
utf16le - 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。
-
ucs2 - utf16le 的别名。
-
base64 - Base64 编码。
-
latin1 - 一种把 Buffer 编码成一字节编码的字符串的方式。
-
binary - latin1 的别名。
-
hex - 将每个字节编码为两个十六进制字符。
创建 Buffer 类
Buffer 提供了以下 API 来创建 Buffer 类:
- Buffer.alloc(size[, fill[, encoding]]): 创建了一个长度为 size 字节的 Buffer,相当于申请了 size 字节的内存空间,每个字节的值为 0。
- Buffer.allocUnsafe(size): 建了一个长度为 size 字节的 Buffer,但 Buffer 中可能存在旧的数据,可能会影响执行结果,所以叫 unsafe。
- Buffer.allocUnsafeSlow(size):用于分配给定大小 size 的新 Buffer 实例,但不对其进行初始化。
- Buffer.from(array): 返回一个被 array 的值初始化的新的 Buffer 实例(传入的 array 的元素只能是数字,不然就会自动被 0 覆盖)
- Buffer.from(arrayBuffer[, byteOffset[, length]]): 返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer。
- Buffer.from(buffer): 复制传入的 Buffer 实例的数据,并返回一个新的 Buffer 实例
- Buffer.from(string[, encoding]): 通过字符串创建 Buffer,可以指定编码,默认为 UTF-8。
实例
// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);
// 创建一个长度为 10、且用 0x1 填充的 Buffer。
const buf2 = Buffer.alloc(10, 1);
// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill() 或 write() 重写。
const buf3 = Buffer.allocUnsafe(10);
// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);
// 创建一个包含 UTF-8 字节 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');
// 创建一个包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1');
写入缓冲区
语法
写入 Node 缓冲区的语法如下所示:
buf.write(string[, offset[, length]][, encoding])
类方法
| 序号 | 方法 & 描述 |
|---|---|
| 1 | listenerCount(emitter, event) 返回指定事件的监听器数量。 |
events.EventEmitter.listenerCount(emitter, eventName) //已废弃,不推荐 events.emitter.listenerCount(eventName) //推荐
基本概念:
- 事件:在程序中发生的动作或状态改变,例如一个文件读取完成或一个 HTTP 请求到达。
- 事件触发器:
EventEmitter是 Node.js 的内置模块,用来发出和监听事件。 - 事件处理器:与事件关联的回调函数,事件发生时被调用。
事件驱动的流程:
- 注册事件:在程序中通过
EventEmitter实例注册事件和对应的处理器。 - 触发事件:当指定的事件发生时,
EventEmitter会触发该事件。 - 处理事件:事件循环会调度相应的回调函数来执行任务。
创建 hello.js 文件,代码如下所示:
实例 1
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
// 注册事件处理器
myEmitter.on('greet', () => {
console.log('Hello, world!');
});
// 触发事件
myEmitter.emit('greet');
更多推荐


所有评论(0)