node.js本地模块
2017-12-18 22:23
274 查看
nodejs有三种模块:内建模块(c++)、本地模块、用户模块
内建模块:使用c++编写,源码文件夹下src目录下很多node_开头的文件就是内建模块
本地模块:使用js编写,源码文件夹下lib目录下的都是本地模块,以上两种模块都会被编译到node二进制命令文件中去
用户模块:node_modules目录下的就是,分为全局安装和非全局的
本地模块的定义:
1.本地模块一开始只缓存了字符串脚本
2.有一个特殊的native_module并没有对应的js文件
3.internal文件夹下模块是否可用需要根据配置决定
4.模块脚本要被包裹为一个匿名函数定义来执行
5.包裹函数参数有exports、require、module、process等等,这里解释了在模块文件中exports与module.exports不能随意混用的原因,
内建模块:使用c++编写,源码文件夹下src目录下很多node_开头的文件就是内建模块
本地模块:使用js编写,源码文件夹下lib目录下的都是本地模块,以上两种模块都会被编译到node二进制命令文件中去
用户模块:node_modules目录下的就是,分为全局安装和非全局的
本地模块的定义:
./lib/bootstrap_node.js
const ContextifyScript = process.binding('contextify').ContextifyScript; //根据字符串代码,获取其中定义的匿名函数 function runInThisContext(code, options) { const script = new ContextifyScript(code, options); return script.runInThisContext(); } //本地模块类,与普通模块相比,没有子模块,因为在其中不调用其他模块 //本地模块指的是源代码目录下lib子目录下的js模块 function NativeModule(id) { this.filename = `${id}.js`; this.id = id; //导出对象 this.exports = {};
//是否已加载 this.loaded = false;
//是否正在加载 this.loading = false; } //本地模块脚本存储,c++中加载脚本,作为字符串存储 NativeModule._source = process.binding('natives'); //模块实例缓存 NativeModule._cache = {}; //内建配置对象 const config = process.binding('config'); //require函数,用来获取本地模块,也可以获取NativeModule类
//注意require获取'native_module'时并不是获取对应的js文件 NativeModule.require = function(id) { if (id === 'native_module') { return NativeModule; } //先从缓存中获取 const cached = NativeModule.getCached(id); //如果获取到,且已加载或正在加载,直接返回导出对象 if (cached && (cached.loaded || cached.loading)) { return cached.exports; } //不包含指定模块,抛出错误 if(!NativeModule.exists(id)) { // Model the error off the internal/errors.js model, but // do not use that module given that it could actually be // the one causing the error if there's a bug in Node.js const err = new Error(`No such built-in module: ${id}`); err.code = 'ERR_UNKNOWN_BUILTIN_MODULE'; err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]'; throw err; } //模块加载列表加入代表本地模块的字符串 process.moduleLoadList.push(`NativeModule ${id}`); //构造本地模块 const nativeModule = new NativeModule(id); //将本地模块实例缓存到构造函数上 nativeModule.cache(); //编译本地模块,执行脚本获取导出对象 nativeModule.compile(); //返回导出对象 return nativeModule.expo 4000 rts; };
//./lib/dep文件夹下的js模块使用这个函数来获取 NativeModule.requireForDeps = function(id) { if (!NativeModule.exists(id) || // TODO(TimothyGu): remove when DEP0084 reaches end of life. id.startsWith('node-inspect/') || id.startsWith('v8/')) { id = `internal/deps/${id}`; } return NativeModule.require(id); }; //获取指定名称缓存模块 NativeModule.getCached = function(id) { return NativeModule._cache[id]; }; //指定名称本地模块是否存在 NativeModule.exists = function(id) { return NativeModule._source.hasOwnProperty(id); }; //如果配置指明暴露internal文件夹下模块 if (config.exposeInternals) { //不区分是否是内部模块 NativeModule.nonInternalExists = NativeModule.exists; //则没有模块是内部模块 NativeModule.isInternal = function(id) { return false; }; } //如果不暴露内部模块 else { //当模块存在且不是内部模块时返回true NativeModule.nonInternalExists = function(id) { return NativeModule.exists(id) && !NativeModule.isInternal(id); }; //模块id以internal开头为内部模块 NativeModule.isInternal = function(id) { return id.startsWith('internal/'); }; } //根据id获取本地模块脚本字符串 NativeModule.getSource = function(id) { return NativeModule._source[id]; }; //包裹本地模块脚本 NativeModule.wrap = function(script) { return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; }; //用于包裹的字符串,最后会被包裹为一个括号括住的匿名函数表达式 NativeModule.wrapper = [ '(function (exports, require, module, internalBinding, process) {', '\n});' ]; //编译模块,相当于根据模块名初始化,执行获取导出对象 NativeModule.prototype.compile = function() { //获取脚本 var source = NativeModule.getSource(this.id); //包裹脚本 source = NativeModule.wrap(source); //正在加载 this.loading = true; try { //获取本地模块被包裹之后的匿名函数 const fn = runInThisContext(source, { filename: this.filename, lineOffset: 0, displayErrors: true }); //获取对应的require函数 const requireFn = this.id.startsWith('internal/deps/') ? NativeModule.requireForDeps : NativeModule.require; //执行函数,传入当前模块实例的属性 fn(this.exports, requireFn, this, internalBinding, process); //已加载 this.loaded = true; } finally { this.loading = false; } }; //在构造函数上缓存本地模块 NativeModule.prototype.cache = function() { NativeModule._cache[this.id] = this; };
1.本地模块一开始只缓存了字符串脚本
2.有一个特殊的native_module并没有对应的js文件
3.internal文件夹下模块是否可用需要根据配置决定
4.模块脚本要被包裹为一个匿名函数定义来执行
5.包裹函数参数有exports、require、module、process等等,这里解释了在模块文件中exports与module.exports不能随意混用的原因,
相关文章推荐
- [快速掌握]Node.js模块封装及本地使用以及发布
- Node.js 模块之【passport】进行本地【用户名+密码】鉴权(一)
- nodejs require本地模块的一些细节笔记
- Node.js12 Http模块
- Node.js readline模块与util模块的使用
- Node.js 使用async模块
- Node.js---02、node.js 模块加载机制
- Node.js模块定义总结
- node.js的模块引用
- 你应该知道的Node.js扩展模块——Hashish
- Node.js本地文件操作之文件拷贝与目录遍历的方法
- Node.js的cluster模块——Web后端多进程服务
- node.js缺少mysql模块运行报错的解决方法
- Node.JS核心模块之全局对象和常用工具
- Node.Js中核心模块之文件系统解析
- Node.js 模块的应用
- node.js如何获取request模块中异步函数回调的返回值
- Node.JS 异步模块的使用
- 深入浅出Node.js(三):深入Node.js的模块机制
- node.js的http模块输出request参数