Node.js源码分析-start-js部分欢迎来到我的博客阅读:《Node.js源码解析-启动-js部分》Node.jsversion8.x当Node.js进程启动时,首先执行c/c++代码,然后c/c++加载并执行lib/internal/bootstrap_node.js,并给出一个进程参数(运行上下文)//lib/internal/bootstrap_node.jsoverview//大家好,欢迎来到hackingnode。js!////该文件由src/node.cc中的node::LoadEnvironment调用,//负责引导node.js核心。由于对启动过程的性能给予了特别的注意//很多依赖被调用//lazily.'usestrict';//这里的process对象来自c/c++,属于原始数据(function(process){//...startup();})加载lib/internal/bootstrap_node.js后,直接执行startup()functionstartup()//lib/internal/bootstrap_node.jsfunctionstartup(){//下面几行代码让流程具备了EventEmitter的特性,比如on,emit//BEGINconstEventEmitter=NativeModule.require('events');process._eventsCount=0;constorigProcProto=Object.getPrototypeOf(process);Object.setPrototypeOf(process,Object.create(EventEmitter.prototype,{constructor:Object.getOwnPropertyDescriptor(origProcProto,'constructor')}));//等同于newEventEmitter(),但是上下文是processEventEmitter.call(process);//END//一些初始化操作//BEGINsetupProcessObject();//尽早做好这件事,因为它会处理错误。setupProcessFatal();setupProcessICUVersions();设置全局变量();如果(!process._noBrowserGlobals){setupGlobalTimeouts();设置全局控制台();}////进程对象的初始化//BEGIN//这里的internal/process模块??用来初始化进程const_process=NativeModule.require('internal/process');_process.setup_hrtime();_process.setup_cpuUsage();_过程。设置内存使用();_process.setupConfig(NativeModule._source);NativeModule.require('内部/进程/警告').setup();NativeModule.require('internal/process/next_tick').setup();NativeModule.require('internal/process/stdio').setup();_process.setup杀死并退出();_process.setupSignalHandlers();if(global.__coverage__)NativeModule.require('internal/process/write-coverage').setup();if(process.argv[1]!=='--debug-agent')_process.setupChannel();_process.setupRawDebug();NativeModule.require('内部/url');Object.defineProperty(process,'argv0',{enumerable:true,configurable:false,value:process.argv[0]});process.argv[0]=process.execPath;//...//END//下面的if-else是用来判断node的运行方式的,我们只关注nodexx.js的运行方式//if(){//...}else{//执行用户代码//集群模块的钩子if(process.argv[1]&&process.env.NODE_UNIQUE_ID){constcluster=NativeModule.require('cluster');cluster._setupWorker();//确保它不会被子进程意外继承。删除process.env.NODE_UNIQUE_ID;}if(process._eval!=null&&!process._forceRepl){//...}elseif(process.argv[1]&&process.argv[1]!=='-'){//nodeapp.js//使process.argv[1]成为完整路径constpath=NativeModule.require('path');//成为绝对路径process.argv[1]=path.resolve(process.argv[1]);constModule=NativeModule.require('module');//检查用户是否向Node.js传递了`-c`或`--check`参数。if(process._syntax_check_only!=null){constfs=NativeModule.require('fs');//读取源代码constfilename=Module._resolveFilename(process.argv[1]);varsource=fs.readFileSync(文件名,'utf-8');checkScriptSyntax(来源,文件名);进程.退出(0);预加载模块();模块.runMain();}else{//REPL或其他}}}startup()最后调用Module.runMain()函数加载并执行用户代码在执行startup()任数的过程中,多次使用了NativeModule.require()来加载模块NativeModuleNativeModule.require()是专门用来加载Node.js内部模块的//lib/internal/bootstrapj(id){this.filename=`${id}.js`;这个.id=id;this.exports={};this.loaded=false;this.loading=false;}NativeModule._source=process.binding('natives');NativeModule._cache={};NativeModule.require=function(id){if(id==='native_module'){returnNativeModule;}constcached=NativeModule.getCached(id);如果(缓存&&(缓存.加载||缓存.加载)){返回缓存.导出;}if(!NativeModule.exists(id)){//从internal/errors.js模型中模拟错误,但是//不要使用那个模块,因为它实际上可能是//如果有Node.js中的错误consterr=newError(`Nosuchbuilt-inmodule:${id}`);err.code='ERR_UNKNOWN_BUILTIN_MODULE';err.na我='错误[ERR_UNKNOWN_BUILTIN_MODULE]';抛出错误;}process.moduleLoadList.push(`NativeModule${id}`);constnativeModule=newNativeModule(id);nativeModule.cache();nativeModule.compile();返回nativeModule.exports;};NativeModule.getCached=function(id){returnNativeModule._cache[id];};NativeModule.exists=function(id){returnNativeModule._source.hasOwnProperty(id);};//...NativeModule.wrap=function(script){returnNativeModule.wrapper[0]+script+NativeModule.wrapper[1];};NativeModule.wrapper=['(函数(导出,要求,模块,__filename,__dirname){','\n});'];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;}};NativeModule.prototype.cache=function(){NativeModule._cache[this.id]=this;};NativeModule有几个重要的属性和方法:id:NativeModule标识,如events,internal/processfilename:NativeModule对应的源代码文件exports:默认值为{}loaded/loading:NativeModulestatus_cache:简单模块cache_source:模块源代码资源require():先查询缓存,如果没有缓存,则新建一个NativeModule并编译,返回exportswrap()/wrapper:wrapper是模块上下文的封装,如下:(function(exports,require,module,__filename,__dirname){xxx});compile():将模块源码用wrapper包装后,使用runInThisContext()(类似eval())生成js函数,然后执行Module.runMain()Node.js启动完成后,调用Module.runMain(),源码如下://bootstrapmainmodule.Module.runMain=function(){//加载主模块--命令行参数。Module._load(process.argv[1],null,true);//处理在程序process._tickCallback();};Module._load()load的第一个tick中添加的任何nextTicks并且执行用户代码至此start-js部分已经完成,后续模块加载部分,详见Node.js源码分析-require后面的start只是Node.js源码的一小部分,另外还有大量内置模块和c/c++源码参考:https://github.com/nodejs/node/blob/master/lib/internal/bootstrap_node.js
