Node的模块加载
Node的REPL
R:读
E:eval计算
P:写
L:loop
console
标准流 1
- console.log()
- console.info()
错误流2 - console.warn()
- console.error()
测试时间
console.time('a')
console.timeEnd('a')
//TDD测试驱动开发、BDD行为驱动开发,单元测试
断言
console.assert()
如果表达式表达为真就不输出,为假就报错,用于监控
function sun(a,b){
return a+b
}
console.assert(sum(1,2)==3,'报错')
console.dir()
//可以列出对象的的结构
console.trace();
//可以跟踪当前代码的调用栈
//程序执行从上往下执行,栈是先进后出
global全局对象
window里也有全局对象,但是不能直接访问,我们在浏览器里访问global是通过window实现的
1.global的变量是全局变量
2.所有的全局变量都是global的属性
console.log(global)
//chdir:改变目录
//cwd:当前工作目录
- process当前进程
process.cwd()
process.chdir()
nextTick 把回调函数放在当前执行栈的底部
setImmediate把回调函数放在事件队列的尾部
回顾 简易版的模块加载
const fs = require('fs');
const path = require('path');
const vm = require('vm')
class Module {
constructor(filepath) {
this.id = filepath;
this.exports = {};
}
load() {
//读取文件:
let fileContent = fs.readFileSync(this.id, 'utf8');
//包装文件
fileContent = '(function(exports,module,require){' + fileContent + '})';
let fn = vm.runInThisContext(fileContent);
fn(this.exports, this, req);
return this.exports;
}
}
function req(filepath) {
//文件的路径:
let absolutepath = path.join(__dirname, filepath);
let module = new Module(absolutepath);
//加载模块
return module.load();
}
const a = req('./a.js');
console.log(a);//hello
升级版
添加对json的处理
添加缓存
const fs = require('fs');
const path = require('path');
const vm = require('vm')
const ModuleCache = {};
class Module {
constructor() {
this.id = "";
this.exports = {};
}
processFile() {
return {
".js":(filepath)=> {
let fileContent = fs.readFileSync(filepath, 'utf8');
fileContent = `(function(module,exports,require,__filename,__dirname){${fileContent}})`;
let fn = vm.runInThisContext(fileContent);
fn(this, this.exports, req, filepath, path.dirname(filepath));
},
".json":(filepath)=> {
let fileContent = fs.readFileSync(filepath, 'utf8');
this.exports = JSON.parse(fileContent);
}
}
}
load(filepath) {
filepath = this.getFileAbsoultePath(filepath);
this.id = filepath;
//判断是否缓存过了
if (ModuleCache[this.id]) {
//加载过了
return ModuleCache[this.id].exports;
}
let extname = path.extname(filepath);
this.processFile()[extname](filepath);
//添加缓存
ModuleCache[this.id] = this;
return this.exports;
}
getFileAbsoultePath(filepath) {
//判断是否有后缀名
//如果有直接使用
//如果没有 匹配后缀
if (filepath.indexOf('/') != 0) {
//传入的是相对路径
filepath = path.join(__dirname, filepath);
console.log("filepath===>",filepath);
}
let extname = path.extname(filepath);
if (!extname) {
let canProcessExtnames = Reflect.ownKeys(this.processFile());
for (let index = 0; index < canProcessExtnames.length; index++) {
const currentExtname = canProcessExtnames[index];
filepath += currentExtname;
if (fs.existsSync(filepath)) {
//找到文件了
break;
} else {
filepath = null;
}
}
} else {
//自带了后缀名
if (!fs.existsSync(filepath)) {
throw new Error("not find file");
}
}
if (filepath) {
return filepath;
}
throw new Error('not find file')
}
}
function req(filepath) {
let module = new Module();
return module.load(filepath);
}
const a = req("./a");
console.log(a);//hello
exports 和 module.exports的关系
console.log(exports===module.exports);//true
// 实际上的形参 和实参 是这样的
let fn=function(module,exports,require,__filename,__dirname){xxxx}
fn(module,module.exports,require,xx,xx);
//可以看到 exports就是module的属性
//但问题是 为什么不能写成
//a.js文件
exports 'hello'
//根据关系我们可以模拟出下面的代码
var obj={arr:[1,2,3]}
var arr=obj.arr;
arr=[4,5,6]
// 这时候的arr和obj.arr还相同吗
// 我们用obj.arr能用到[4,5,6]吗
模块的加载顺序
文件模块
- 通过文件的路径找对应的文件 如果文件存在,则加载文件
- 如果文件不存在,则找同名文件夹/index.js文件
第三方模块
- 通过名称在自己的目录的
node_modules
中找对应的文件夹 - 找到该文件夹下的package.json文件中的main字段对应的文件加载文件
- 如果没有package.json 或是没有main字段,则会默认找文件夹下的
index.js或index.json
文件并加载 - 如果还找不到,则再向上一层查找
node_modules
文件夹
内置模块
- 通过名称引用 优先引用
网友评论