理解理解 Node.js 事件驱动机制的原理事件驱动机制的原理
学习 Node.js 一定要理解的内容之一,文中主要涉及到了 EventEmitter 的使用和一些异步情况的处理,比较偏基础,值得一
读。
大多数 Node.js 对象都依赖了 EventEmitter 模块来监听和响应事件,比如我们常用的 HTTP requests, responses, 以及
streams。
const EventEmitter = require('events');
事件驱动机制的最简单形式,是在 Node.js 中十分流行的回调函数,例如 fs.readFile。 在回调函数这种形式中,事件每被触
发一次,回调就会被触发一次。
我们先来探索下这个最基本的方式。
你准备好了就叫我哈,你准备好了就叫我哈,Node!!
很久很久以前,在 js 里还没有原生支持 Promise,async/await 还只是一个遥远的梦想,回调函数是处理异步问题的最原始的
方式。
回调从本质上讲是传递给其他函数的函数,在 JavaScript 中函数是第一类对象,这也让回调的存在成为可能。
一定要搞清楚的是,回调在代码中的并不表示异步调用。 回调既可以是同步调用的,也可以是异步调用的。
举个例子,这里有一个宿主函数 fileSize,它接受一个回调函数 cb,并且可以通过条件判断来同步或者异步地调用该回调函
数:
function fileSize (fileName, cb) {
if (typeof fileName !== 'string') {
// Sync
return cb(new TypeError('argument should be string'));
}
fs.stat(fileName, (err, stats) => {
if (err) {
// Async
return cb(err);
}
// Async
cb(null, stats.size);
});
}
这其实也是个反例,这样写经常会引起一些意外的错误,在设计宿主函数的时候,应当尽可能的使用同一种风格,要么始终都
是同步的使用回调,要么始终都是异步的。
我们来研究下一个典型的异步 Node 函数的简单示例,它用回调样式编写:
const readFileAsArray = function(file, cb) {
fs.readFile(file, function(err, data) {
if (err) {
return cb(err);
}
const lines = data.toString().trim().split('');
cb(null, lines);
});
};
readFileAsArray 函数接受两个参数:一个文件路径和一个回调函数。它读取文件内容,将其拆分成行数组,并将该数组作为
回调函数的参数传入,调用回调函数。
现在设计一个用例,假设我们在同一目录中的文件 numbers.txt 包含如下内容:
10
11
12
13
14
15
如果我们有一个需求,要求统计该文件中的奇数数量,我们可以使用 readFileAsArray 来简化代码: