1.先从Nodejs的入口谈起,一下采纳的是nodejs 6.9.4 版本。
nodejs启动的入口文件src/node_main.cc

// UNIXint main(int argc, char *argv[]) {  // Disable stdio buffering, it interacts poorly with printf()  // calls elsewhere in the program (e.g., any logging from V8.)  setvbuf(stdout, nullptr, _IONBF, 0);  setvbuf(stderr, nullptr, _IONBF, 0);  return node::Start(argc, argv);}

由代码可看出,次要运行的是node::Start办法,此办法定义在src/node.cc文件中。

int Start(int argc, char** argv) {  PlatformInit();  CHECK_GT(argc, 0);  // Hack around with the argv pointer. Used for process.title = "blah".  argv = uv_setup_args(argc, argv);  // This needs to run *before* V8::Initialize().  The const_cast is not  // optional, in case you're wondering.  int exec_argc;  const char** exec_argv;  Init(&argc, const_cast<const char**>(argv), &exec_argc, &exec_argv);#if HAVE_OPENSSL#ifdef NODE_FIPS_MODE  // In the case of FIPS builds we should make sure  // the random source is properly initialized first.  OPENSSL_init();#endif  // NODE_FIPS_MODE  // V8 on Windows doesn't have a good source of entropy. Seed it from  // OpenSSL's pool.  V8::SetEntropySource(crypto::EntropySource);#endif  v8_platform.Initialize(v8_thread_pool_size);  V8::Initialize();  int exit_code = 1;  {    NodeInstanceData instance_data(NodeInstanceType::MAIN,                                   uv_default_loop(),                                   argc,                                   const_cast<const char**>(argv),                                   exec_argc,                                   exec_argv,                                   use_debug_agent);    StartNodeInstance(&instance_data);    exit_code = instance_data.exit_code();  }  V8::Dispose();  v8_platform.Dispose();  delete[] exec_argv;  exec_argv = nullptr;  return exit_code;}

此办法开端处调用了同一个文件中的StartNodeInstance办法,传入一个NodeInstanceData(node_internals.h中定义)实例,在这个办法中调用了LoadEnvironment办法,LoadEnvironment办法有如下代码:

  // Execute the lib/internal/bootstrap_node.js file which was included as a  // static C string in node_natives.h by node_js2c.  // 'internal_bootstrap_node_native' is the string containing that source code.  Local<String> script_name = FIXED_ONE_BYTE_STRING(env->isolate(),                                                    "bootstrap_node.js");  Local<Value> f_value = ExecuteString(env, MainSource(env), script_name);  if (try_catch.HasCaught())  {    ReportException(env, try_catch);    exit(10);  }  // The bootstrap_node.js file returns a function 'f'  CHECK(f_value->IsFunction());  Local<Function> f = Local<Function>::Cast(f_value);  // Add a reference to the global object  Local<Object> global = env->context()->Global();#if defined HAVE_DTRACE || defined HAVE_ETW  InitDTrace(env, global);#endif#if defined HAVE_LTTNG  InitLTTNG(env, global);#endif#if defined HAVE_PERFCTR  InitPerfCounters(env, global);#endif  // Enable handling of uncaught exceptions  // (FatalException(), break on uncaught exception in debugger)  //  // This is not strictly necessary since it's almost impossible  // to attach the debugger fast enought to break on exception  // thrown during process startup.  try_catch.SetVerbose(true);  env->SetMethod(env->process_object(), "_rawDebug", RawDebug);  // Expose the global object as a property on itself  // (Allows you to set stuff on `global` from anywhere in JavaScript.)  global->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global);  // Now we call 'f' with the 'process' variable that we've built up with  // all our bindings. Inside bootstrap_node.js and internal/process we'll  // take care of assigning things to their places.  // We start the process this way in order to be more modular. Developers  // who do not like how bootstrap_node.js sets up the module system but do  // like Node's I/O bindings may want to replace 'f' with their own function.  Local<Value> arg = env->process_object();  f->Call(Null(env->isolate()), 1, &arg);

能够看到,这个node通过执行/lib/internal/bootstrap_node.js进行初始化, ExecuteString之后失去的是bootstrap_node的一个对象,将其类型转换成Function,在最初执行之f->Call(Null(env->isolate()), 1, &arg);执行的时候传入的&arg就是process对象的援用。而process对象的设置是在雷同文件的SetupProcessObject函数中设置的,在这个调用过程中在process对象上设置了除bind和dlopen外的简直所有办法和对象。bootstrap_node.js执行初始化的就是Nodejs的module模块零碎。

2.Node启动后会首先加载其外围模块(既纯用C++编写的Nodejs自带模块)。而在js中援用这些模块都是应用process.binding函数进行援用,在process的初始化函数SetupProcessObject中能够看到如下代码:

 env->SetMethod(process, "binding", Binding);

也就是说理论应用的是node.cc文件中的Binding函数,如下:

  node_module* mod = get_builtin_module(*module_v);  if (mod != nullptr) {    exports = Object::New(env->isolate());    // Internal bindings don't have a "module" object, only exports.    CHECK_EQ(mod->nm_register_func, nullptr);    CHECK_NE(mod->nm_context_register_func, nullptr);    Local<Value> unused = Undefined(env->isolate());    mod->nm_context_register_func(exports, unused,      env->context(), mod->nm_priv);    cache->Set(module, exports);  } else if (!strcmp(*module_v, "constants")) {    exports = Object::New(env->isolate());    DefineConstants(env->isolate(), exports);    cache->Set(module, exports);  } else if (!strcmp(*module_v, "natives")) {    exports = Object::New(env->isolate());    DefineJavaScript(env, exports);    cache->Set(module, exports);  } else {    char errmsg[1024];    snprintf(errmsg,             sizeof(errmsg),             "No such module: %s",             *module_v);    return env->ThrowError(errmsg);  }  args.GetReturnValue().Set(exports);

能够看到,是调用get_builtin_module函数来获取编译好的c++模块的,看下get_builtin_module函数:

struct node_module* get_builtin_module(const char* name) {  struct node_module* mp;  for (mp = modlist_builtin; mp != nullptr; mp = mp->nm_link) {    if (strcmp(mp->nm_modname, name) == 0)      break;  }  CHECK(mp == nullptr || (mp->nm_flags & NM_F_BUILTIN) != 0);  return (mp);}

能够看到,这个函数在modlist_builtin构造中寻找对应输出名称的模块并返回。modlist_builtin构造是在node_module_register函数(在node.cc文件中被定义)调用时被逐条注册的,而node_module_register调用的中央是在node.h中的宏定义

#define NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, priv, flags)    \  extern "C" {                                                        \    static node::node_module _module =                                \    {                                                                 \      NODE_MODULE_VERSION,                                            \      flags,                                                          \      NULL,                                                           \      __FILE__,                                                       \      NULL,                                                           \      (node::addon_context_register_func) (regfunc),                  \      NODE_STRINGIFY(modname),                                        \      priv,                                                           \      NULL                                                            \    };                                                                \    NODE_C_CTOR(_register_ ## modname) {                              \      node_module_register(&_module);                                 \    }                                                                 \  }
#define NODE_MODULE_CONTEXT_AWARE_BUILTIN(modname, regfunc)           \  NODE_MODULE_CONTEXT_AWARE_X(modname, regfunc, NULL, NM_F_BUILTIN)   \

在每个src目录下的c++模块都会在结尾处调用NODE_MODULE_CONTEXT_AWARE_BUILTIN,也就是在模块被引入后就会将模块注册到modlist_builtin中去。供后续被其余模块援用。