node核心设计模式
文章目录
references:
《Node.js 设计模式(第 2 版)》【爱尔兰】Mario Casciaro(马里奥•卡西罗) / 【意大利】Luciano Mammino(卢西安诺•马米诺)
简单介绍
node哲学思想
- 小核心:保持核心功能的最小集合。
- 小模块:在NPM(官方软件包管理器)的帮助下,node可以解决依赖地狱问题。==> Don’t repeat yourself
- 小接触面
es6的一点知识
// 关于 weakMap和weakSet
let obj={};
const map=new WeakMap();
map.set(obj,{key:'some_value'});
console.info(map.get(obj));
// 只剩下引用的时候,对象作为主键可以用来进行垃圾回收
obj=undefined; // now obj and the associated data in the map will be cleaned up in the next gc cycle
console.info(map);
let obj1={key:'val1'};
let obj2={key:'val2'};
const set=new WeakSet([obj1,obj2]);
console.info(set.has(obj1));
// 只剩下引用的时候被垃圾回收
obj1=undefined; // now obj1 will be removed from the set
console.info(set.has(obj1));
reactor模式
阻塞I/O
传统的阻塞I/O编程,与I/O请求相对应的函数调用将阻塞线程的执行。
非阻塞I/O
这种模式下,系统调用总是立即返回,而无需等待数据读取或者写入。访问这种非阻塞I/O的最基本模式是在循环内主动轮询资源,直到返回一些实际数据即忙碌等待。
reactor模式通过阻塞来处理I/O,直到一组被观察资源的新事件可用,然后将每个事件分派到相关联的处理程序来作出反应。
]
其中「绑定」是用来负责包装和暴露libuv和JavaScript其他低级功能。
node基本设计模式
node回调约定
- 回调函数置于尾部
- 暴露错误优先
fs.readFile('foo.txt','utf8',(err,data)=>{
if(err){
handleError(err);
}else{
process(data);
}
})
- 传播错误:传播错误时建议使用
return
语句,这样可以确保一旦回调函数函数被调用就退出函数。 - 未捕获异常
// todo 说实话没有看懂
模块系统及其模式
node模块遵循commonJS模块规范
- require函数是同步的,因此module.exports也是同步的
- 解析算法
- 文件模块
- 核心模块
- 包模块
对于文件和包模块,单个文件和目录都可以与moduleName匹配,特别的,解析算法将尝试匹配以下内容: - .js
- /index.js
- 在/package.json的main属性中制定的目录/文件
导出函数
将整个module.exports变量重新分配给一个函数。
module.exports=(message)=>{
console.info(`info:${message}`);
}
// 扩展
module.exports.verbose=message=>{
console.info(`verbose:${message}`);
}
node 提倡单一职责原则:(single responsibility principle,SRP)
导出实例
// Logger是一个构造函数
module.exports.logger=Logger;
观察者模式
EventEmitter类允许我们将一个或者多个函数注册为监听器,当一个特定的事件类型被触发时,它将被调用。
references:
// EventEmitter简单实现,但是真正的源码处理了很多边界条件,具体可以参考:https://www.jianshu.com/p/3dc51474c96c
function EventEmitter() {
this.events = {}; //所有事件监听函数放在这个对象里保存
this._maxListeners = 10; //监听函数最多10个
}
//给制定函数绑定事件处理函数
EventEmitter.prototype.on = EventEmitter.prototype.addEventListener = function (type,listener) {
if(this.events[type]){
this.events[type].push(listener);
if(this._maxListeners != 0 && this.events[type].length > this._maxListeners){
console.error('MaxListenersExceededWarning: Possible EventEmitter memory leak detected.\n');
}
}else {
this.events[type] = [listener];
}
};
EventEmitter.prototype.emit = function (type, ...rest) {
if(this.events[type]){
//遍历触发函数数组 apply把this指向当前对象 解构rest
this.events[type].forEach((listener)=>listener.apply(this,rest));
}
};
EventEmitter.prototype.removeListener = function(type,listener) {
if (this.events[type]){
this.events[type] = this.events[type].filter(l=>l!==listener);
//使用filter过滤数组
}
};
有关EventEmitter的一些特点
- 传播错误
为了避免正常出现错误的情况以及事件是异步,事件循环中出现错误的情况,约定发出error
事件并为其注册事件监听器。
const emitter=new EventEmitter();
emitter.on('error',err=>{
console.info(err.message);
})
- 使任何对象可观察
通过扩展EventEmitter
来使任何对象可观察
class Test extends EventEmitter{}