Appearance
Node中的模块
一.commonjs规范
- 1.每个js文件都是一个模块
- 2.模块的导出 module.exports
- 3.模块的导入require
二.node中的模块的分类
- 1.核心模块/内置模块 fs http path 不需要安装 引入的时候不需要增加相对路径、绝对路径
- 2.第三方模块需要安装
- 3.自定义模块需要通过绝对路径或者相对路径进行引入
三.模块实现
实现node中的模块化机制
const fs = require('fs');
const path = require('path');
const vm = require('vm');
function Module(id) {
this.id = id;
this.exports = {};
}
Module.wrapper = [
`(function(exports,require,module,__filename,__dirname){`,
`})`
];
Module._extensions = {
'.js'(module) {
let content = fs.readFileSync(module.id, 'utf8');
content = Module.wrapper[0] + content + Module.wrapper[1];
let fn = vm.runInThisContext(content);
let exports = module.exports;
let dirname = path.dirname(module.id);
fn.call(exports, exports, req, module, module.id, dirname);
},
'.json'(module) {
let content = fs.readFileSync(module.id, 'utf8');
module.exports = JSON.parse(content);
}
}
Module._resolveFilename = function (filename) {
let absPath = path.resolve(__dirname, filename);
let isExists = fs.existsSync(absPath);
if (isExists) {
return absPath;
} else {
let keys = Object.keys(Module._extensions);
for (let i = 0; i < keys.length; i++) {
let newPath = absPath + keys[i];
let flag = fs.existsSync(newPath);
if (flag) {
return newPath;
}
}
throw new Error('module not exists');
}
}
Module.prototype.load = function () {
let extName = path.extname(this.id);
Module._extensions[extName](this);
}
Module._cache = {};
function req(filename) {
filename = Module._resolveFilename(filename);
let cacheModule = Module._cache[filename];
if (cacheModule) {
return cacheModule.exports;
}
let module = new Module(filename);
Module._cache[filename] = module
module.load();
return module.exports;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
四.Events模块
node中自己实现的发布订阅模块,订阅是将方法对应成一种一对多的关系,on方法用来订阅事件
function EventEmitter(){
this._events = Object.create(null);
}
EventEmitter.prototype.on = function(eventName,callback){
if(!this._events) this._events = Object.create(null);
// 如果用户绑定的不是newListener 让newListener的回调函数执行
if(eventName !== 'newListener'){
if(this._events['newListener']){
this._events['newListener'].forEach(fn=>fn(eventName))
}
}
if(this._events[eventName]){
this._events[eventName].push(callback)
}else{
this._events[eventName] = [callback]; // {newListener:[fn1]}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
off方法可以移除对应的事件监听
// 移除绑定的事件
EventEmitter.prototype.off = function(eventName,callback){
if(this._events[eventName]){
this._events[eventName] = this._events[eventName].filter(fn=>{
return fn!=callback && fn.l !== callback
});
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
emit用来执行订阅的事件
EventEmitter.prototype.emit = function(eventName,...args){
if(this._events[eventName]){
this._events[eventName].forEach(fn => {
fn.call(this,...args);
});
}
}
1
2
3
4
5
6
7
2
3
4
5
6
7
once绑定事件当执行后自动删除订阅的事件
EventEmitter.prototype.once = function(eventName,callback){
let one = (...args)=>{
callback.call(this,...args);
// 删除掉这个函数
this.off(eventName,one); // 执行完后在删除掉
}
one.l = callback; // one.l = fn;
// 先绑定一个once函数,等待emit触发完后执行one函数 ,执行原有的逻辑,执行后删除once函数
this.on(eventName,one);
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10