本章主要讲的是
如何用模块组织代码;
异步编程的两种方式,回调和事件发射器;
异步逻辑的串行和并行控制方式;
1. 模块组织代码 module
- Node模块打包代码是为了重用,但它不会污染全局作用域。模块允许从被引入文件中选择需要的函数和变量。
- 模块即可以是一个文件,也可以是多个文件的目录。 如果模块是一个目录,Node默认会在这个目录下寻找一个叫index.js文件, 你也可以在这个目录下使用package.json文件指定模块的入口
- 引入模块时,使用Node的
require
函数, 这个函数接收一个路径作为参数。 Node会以同步的方式,寻找文件,并加载文件内容。 查找顺序是 核心模块 -> 当前目录-> node_modules - 由于require是同步的,所以在I/O密集的地方应该尽量避免使用。同步操作通常放在程序最初加载的地方
-
exports
是对module.exports
的一个全局引用,被定义为一个可以添加属性的空对象。 真正导出的是module.exports
。 因此导出对象时需要使用module.exports
, 如果直接使用exports
将会打破引用, 无法导出。
module.exports = MyClass
//或者
module.exports = exports = MyClass
- 同一个进程里
require
同一个模块得到的是相同的对象。Node能把模块作为对象缓存起来。如果程序里有两个文件引入了同一个模块,第一个require
会把模块返回的数据保存到内存中,这样第二个require
就可以直接从内存中取出来,不用再去寻找和运行模块了。
2. 回调
- 回调通常用于处理一次性相应的逻辑。比如对于一次数据库查询,可以指定一个回调函数来处理查询的结果。
- 通过创建中间函数来减少回调嵌套,便于测试、维护
- 通过尽早返回(
return
)来减少嵌套
3. 事件监听器
- 事件监听器本质上也是一个回调,不同之处是,它跟一个事件关联。例如Node的TCP socket,它有一个data事件, 当socket中有新数据就会触发,我们可以这样监听这个事件:
socket.on('data', handleData)
一个简单的聊天室例子
const event = require("events");
const net = require("net");
const channel = new event.EventEmitter();
channel.clients = {};
channel.subscription = {};
channel.on("join", function(id, client) {
// 保存client连接
this.clients[id] = client;
// 定义每个client的subscription方法, 如果sender不是自己就发送message
this.subscription[id] = (sender_id, message) => {
if (id != sender_id) {
this.clients[id].write(message);
}
};
/*
每次客户端join进来都会使用上面定义subscription方法来绑定到broadcast事件
有n个client连进来,这个broadcast事件就被监听n次,发射时,也会触发n次回调函数
*/
this.on("broadcast", this.subscription[id]); //broadcast事件处理回调
});
channel.on("leave", function(id) {
channel.removeListener("broadcast", this.subscription[id]);
channel.emit("broadcast", id, `${id} has left the chatroom \n`);
});
const server = net.createServer(client => {
const id = `${client.remoteAddress}:${client.remotePort}`;
channel.emit("join", id, client);
client.on("data", data => {
data = data.toString();
// 当接收到客户端发来的数据时,向channel发射broadcast事件
channel.emit("broadcast", id, data);
});
client.on("close", () => {
channel.emit("leave", id);
});
});
server.listen(8888);