37、加载json的处理流程
useA.js
分析node源码:
1、会默认调用require语法
2、Module.prototype.require模块的原型上有require方法
3、Module._load调用模块的加载方法,最终返回的是module.exports
4、Module._resolveFilename解析文件名 ,将文件名变成绝对路径,默认尝试添加.js/.json/.node
5、Module.__cache默认会判断是否存在缓存
6、new Module创建模块(对象) id, exports
7、把模块缓存起来,方便下次使用
--------------根据文件名(绝对路径)创建一个模块
8、tryModuleLoad 尝试加载模块 module.load
9、module.paths第三方模块查找的路径
10、获取当前模块的扩展名 根据扩展名调用对应的方法 Module.__extensions策略模式
11、获取文件的内容
12、调用Module.__compile方法
13、将用户的内容包裹到一个函数中(function (exports,require,module,__filename,__dirname){})
//最终返回的是module.exports,用户会给这个module.exports进行赋值
const path = require('path');
const fs = require('fs');
const vm = require('vm');
function Module(id)
{
this.id = id;
this.exports = {};
}
Module.wrap=function(script){
let arr = [
'(function(exports,require,module,_filename,_dirname){',
script,
'})'
];
return arr.join('');
}
Module._extensions = {
'js':function(module){
let content = fs.readFileSync(module.id,'utf8');
console.log(content);
console.log('js',module);
let fnstr = Module.wrap(content);
console.log(fnstr);
let fn = vm.runInThisContext(fnstr);
let exports = module.exports;
let require = myRequire;
let _filename = module.id;
let _dirname = path.dirname(module.id);
//fn.call(exports); //这里的this就是exports对象
fn.call(exports,exports,require,module,_filename,_dirname);
//用户会给module.exports赋值
},
'json':function(module){
let content = fs.readFileSync(module.id);
module.exports = JSON.parse(content); //读取出来的是字符串
}
};
Module._resolveFilename = function(filepath){
//根据当前路径实现解析
let filePath = path.resolve(__dirname,filepath);
let exists = fs.existsSync(filePath);//判断当前文件是否存在
if(exists)return filePath; //如果存在直接返回路径
//尝试添加后缀(forEach不能停止)
let keys = Object.keys(Module._extensions);
for(let i =0; i< keys.length;i++){
let currentPath = filePath + keys[i];
if(fs.existsSync(currentPath)){ //尝试添加后缀查找
return currentPath;
}
}
//throw new Error('模块不存在');
}
Module._load = function(filepath){
let filename = Module._resolveFilename(filepath);//将路径转换成绝对路径
console.log(filename);
let module = new Module(filename);//保证每个模块的唯一性,需要通过唯一路径进行查找
module.load(filename);
return module.exports; //id,exports对应的就是当前模块的结果
}
Module.prototype.load = function(filename){
//获取文件的后缀来进行加载
let extname = path.extname(filename);
Module._extensions[extname](this);//根据对应的后缀名进行加载
}
function myRequire(filepath){
//根据路径加载这个模块
return Module._load(filepath);
}
//myRequire = require;
let r = myRequire('./a');
console.log(r);
a.js
let a =1;
console.log(this === module.exports);//true
module.exports = a;
useA.js
require('./a');
a.js
let a = 1;
this.a = a; 三种方式都可以
//exports.a = a;
//module.exports.a = 1
useA.js
let r = require('./a');
console.log(r);
//exports='hello' 你改变exports属性不会导致module.exports变化
//最终导出的是module.exports
//exports.a = 'hello',会通过引用找到空间添加属性,导致module.exports发生变化
module.exports = 'hello';
exports.a = 1;
Module.cache = {}
Module._load = function(filepath){
let filename = Module._resolveFilename(filepath);
//获取路径后不要立即创建模块,先看一眼能否找到以前加载过的模块
if(Module.cache[filename]){
return Module.cache[filename].exports;//直接返回上一次返回的模块
}
let module = new Module(filename);
Module.cache[filename] = module;
module.load(filename);
return module.exports;
}
*/
}