一提到nodejs中的模块,大家就会想到用require来添加引用那个模块。看了很多博客,明白了加载机制,脑子里一直知道每个文件都会'(function(exports,require,module,__filename,__dirname){',//文件的源代码'n});'打包,文件里自然有require命令。前几天看了模块的源码https://github.com/nodejs/nod...module.js源码前几行constNativeModule=require('native_module');constutil=require('util');constinternalModule=require('internal/module');constvm=require('vm');constassert=require('assert').ok;constfs=require('fs');constinternalFS=require('内部/FS');刚上来的时候一头雾水,module.js不就是为了实现require吗?为什么一上来就用require去引用其他模块,从而陷入死循环。在一些技术网站上提问https://cnodejs.org/topic/58b...虽然还是不是很懂,但是有了一些思路,然后又开始看源码,开始了调试,终于弄明白了。所以我想把我的整个过程写下来记录下来。1、module.js前几行的require从哪里来?写两个js文件,a.jsconstb=require('./b.js');b.jsexports.done=false;node执行a.js首先,node启动的时候会执行第一个js文件https://github.com/nodejs/nod...这个文件会在module.js的第一行定义NativeModule。可以看到NativeModule函数的定义NativeModule(id){this.filename=`${id}.js`;this.id=id;this.exports={};this.loaded=false;this.loading=false;从入口函数启动可以看到constModule=NativeModule.require('module');也就是说会加载module.js模块。在require函数中NativeModule.require=function(id){if(id==='native_module'){returnNativeModule;}/.../constnativeModule=newNativeModule(id);创建一个新的NativeModule对象nativeModule.cache();nativeModule.compile();//主要步骤returnnativeModule.exports;};在编译NativeModule.prototype.compile=function(){varsource=NativeModule.getSource(this.id);source=NativeModule.wrap(source);this.loading=true;try{constfn=runInThisContext(source,{filename:this.filename,lineOffset:0,displayErrors:true});fn(this.exports,NativeModule.require,this,this.filename);this.loaded=true;}最后{this.loading=false;}};wrap将包装文件NativeModule.wrap=function(script){returnNativeModule.wrapper[0]+script+NativeModule.wrapper[1];};NativeModule.wrapper=['(function(exports,require,module,__filename,__dirname){','\n});'];其中require是NativeModule.require然后会执行Module.runMain函数,从而进入module.js,所以module.js开头的require是NativeModule.require,不矛盾2.a.js的执行执行a.js时会进入module.jsModule.runMain=function(){//加载主模块--命令行参数.Module._load(process.argv[1],null,true);//处理在程序的第一个tick中添加的任何nextTicksprocess._tickCallback();};调用Module._load函数,process.argv[1]是一个.js模块。runMain->Module._load->tryModuleLoad->module.load->Module._extensions['.js']->module._compileinmodule._compilevarwrapper=Module.wrap(content);此时只调用NativeModule的wrap函数就可以把a.js包起来就行了然后varrequire=internalModule.makeRequireFunction.call(this);会通过https://github.com/nodejs/node/blob/master/lib/internal/module.js的makeRequireFunction函数创建一个require函数,functionrequire(path){try{exports.requireDepth+=1;returnself.require(path);}finally{exports.requireDepth-=1;}}call.(this)指向模块的指针,所以a.js包头中的require就是makeRequireFunction返回的require,self.要求(路径);将调用Module.prototype.requireModule.prototype.require=function(path){returnModule._load(path,this,/*isMain*/false);};require会调用Module._load来加载其他模块。这是几个require之间的关系。新人第一次写,如有错误请指正。参考:https://github.com/nodejs/nod...https://github.com/nodejs/nod...https://github.com/nodejs/nod...
