Node.js 是如何跑起来的( 二 )

初始化 Libuv这里对事件循环的部分阶段做一些初始化的操作,创建一个默认的 event_loop 结构体用于管理后续各个阶段产生的任务
void Environment::InitializeLibuv(bool start_profiler_idle_notifier) {HandleScope handle_scope(isolate());Context::Scope context_scope(context());CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));uv_check_init(event_loop(), immediate_check_handle());uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));uv_idle_init(event_loop(), immediate_idle_handle());uv_check_start(immediate_check_handle(), CheckImmediate);uv_prepare_init(event_loop(), &idle_prepare_handle_);uv_check_init(event_loop(), &idle_check_handle_);uv_async_init(event_loop(),&task_queues_async_,[](uv_async_t* async) {Environment* env = ContainerOf(&Environment::task_queues_async_, async);env->CleanupFinalizationGroups();env->RunAndClearNativeImmediates();});uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));// ...}执行用户 JS 代码StartExecution 用于加载用户 JS 代码并执行
// src/node.ccMaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {// ...if (!first_argv.empty() && first_argv != "-") {return StartExecution(env, "internal/main/run_main_module");}// ...} // lib/internal/main/run_main_module.jsrequire('internal/modules/cjs/loader').Module.runMain(process.argv[1]);进入 Libuv 事件循环执行完用户 JS 代码,用户代码就会往 Libuv 中注册一些任务,然后进入整个事件循环,直到没有待处理的任务,Libuv 则会退出事件循环,进而退出 NodeJS 进程 。
// src/node_main_instance.ccdo {uv_run(env->event_loop(), UV_RUN_DEFAULT);per_process::v8_platform.DrainVMTasks(isolate_);more = uv_loop_alive(env->event_loop());if (more && !env->is_stopping()) continue;if (!uv_loop_alive(env->event_loop())) {EmitBeforeExit(env.get());}// Emit `beforeExit` if the loop became alive either after emitting// event, or after running some callbacks.more = uv_loop_alive(env->event_loop());} while (more == true && !env->is_stopping());?源代码概览?// src/node_main.ccint main(int argc, char* argv[]) {return node::Start(argc, argv);} // src/node.ccnamespace node {int Start(int argc, char** argv) {InitializationResult result = InitializeOncePerProcess(argc, argv);// ...NodeMainInstance main_instance(&params,uv_default_loop(),per_process::v8_platform.Platform(),result.args,result.exec_args,indexes);result.exit_code = main_instance.Run();}InitializationResult InitializeOncePerProcess(int argc, char** argv) {// ...{result.exit_code =InitializeNodeWithArgs(&(result.args), &(result.exec_args), &errors);//...}V8::Initialize();return result;}int InitializeNodeWithArgs(std::vector<std::string>* argv,std::vector<std::string>* exec_argv,std::vector<std::string>* errors) {// ...// Register built-in modulesbinding::RegisterBuiltinModules();// ...}MaybeLocal<Value> Environment::RunBootstrapping() {EscapableHandleScope scope(isolate_);//...if (BootstrapInternalLoaders().IsEmpty()) {return MaybeLocal<Value>();}Local<Value> result;if (!BootstrapNode().ToLocal(&result)) {return MaybeLocal<Value>();}//...return scope.Escape(result);}} // src/node_main_instance.ccnamespace node {int NodeMainInstance::Run() {// ...DeleteFnPtr<Environment, FreeEnvironment> env =CreateMainEnvironment(&exit_code);if (exit_code == 0) {LoadEnvironment(env.get());// ...{// ...do {uv_run(env->event_loop(), UV_RUN_DEFAULT);per_process::v8_platform.DrainVMTasks(isolate_);more = uv_loop_alive(env->event_loop());if (more && !env->is_stopping()) continue;if (!uv_loop_alive(env->event_loop())) {EmitBeforeExit(env.get());}// Emit `beforeExit` if the loop became alive either after emitting// event, or after running some callbacks.more = uv_loop_alive(env->event_loop());} while (more == true && !env->is_stopping());}}// ...}NodeMainInstance::CreateMainEnvironment(int* exit_code) {// ...context = NewContext(isolate_);Context::Scope context_scope(context);DeleteFnPtr<Environment, FreeEnvironment> env { CreateEnvironment(isolate_data_.get(),context,args_,exec_args_,EnvironmentFlags::kDefaultFlags) };return env;}} // src/environment.ccnamespace node {void LoadEnvironment(Environment* env) {USE(LoadEnvironment(env,StartExecutionCallback{},{}));}MaybeLocal<Value> LoadEnvironment(Environment* env,StartExecutionCallback cb,std::unique_ptr<InspectorParentHandle> removeme) {env->InitializeLibuv(per_process::v8_is_profiling);env->InitializeDiagnostics();return StartExecution(env, cb);}Environment* CreateEnvironment(IsolateData* isolate_data,Local<Context> context,int argc,const char* const* argv,int exec_argc,const char* const* exec_argv) {return CreateEnvironment(isolate_data, context,std::vector<std::string>(argv, argv + argc),std::vector<std::string>(exec_argv, exec_argv + exec_argc));}Environment* CreateEnvironment(IsolateData* isolate_data,Local<Context> context,const std::vector<std::string>& args,const std::vector<std::string>& exec_args,EnvironmentFlags::Flags flags,ThreadId thread_id,std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {Isolate* isolate = context->GetIsolate();HandleScope handle_scope(isolate);Context::Scope context_scope(context);// TODO(addaleax): This is a much better place for parsing per-Environment// options than the global parse call.Environment* env = new Environment(isolate_data,context,args,exec_args,flags,thread_id);// ...if (env->RunBootstrapping().IsEmpty()) {FreeEnvironment(env);return nullptr;}return env;}}


推荐阅读