title: Node.js 源码剖析 - 加载 js 文件
date: 2018-11-30 21:04:49
tags:
- Node.js- Node.js 源码剖析- 源码剖析
categories:
- Node.js 源码剖析
此文最后于四年前公布在集体站上的,现迁徙至此重发,原链接:https://laogen.site/nodejs/no...
《Node.js 源码剖析》 系列目录页:https://laogen.site/nodejs/no...
提出问题
理解 js 文件加载前的筹备工作
在《从 main 函数开始》这篇中说到了 LoadEnvironment()
函数负责加载 js 代码,但并没有持续阐明加载细节。
这篇从 LoadEnvironment()
开始探索 js 代码加载的具体过程。
<!-- more -->
LoadEnvironment()
LoadEnvironment()
的逻辑分两局部:
- 加载并执行两个 js 文件:
loaders.js
node.js
,执行后失去两个启动函数; - 别离调用这两个启动函数:loaders_bootstrapper() 和 node_bootstrapper();
这段代码比拟长,咱们把不影响主逻辑的代码省略掉,而后间接在代码中以正文的模式来解释:
void LoadEnvironment(Environment* env) { // ... /************************************************************/ /**** 第一步.加载并执行两个 js 文件:`loaders.js` `node.js`****/ /************************************************************/ // The bootstrapper scripts are lib/internal/bootstrap/loaders.js and // lib/internal/bootstrap/node.js, each included as a static C string // defined in node_javascript.h, generated in node_javascript.cc by // node_js2c. // 这两个 js 文件在 node 构建过程中就被转换成了 C++ 代码,即以 C++ 字符串的 // 模式存在于 C++ 代码中,依据这个文件名就能够间接获取相应的 js 代码字符串; // loaders.js 的文件名 Local<String> loaders_name = FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/loaders.js"); // 执行 loaders.js 失去函数: `loaders_bootstrapper` MaybeLocal<Function> loaders_bootstrapper = GetBootstrapper(env, LoadersBootstrapperSource(env), loaders_name); // node.js 文件名 Local<String> node_name = FIXED_ONE_BYTE_STRING(env->isolate(), "internal/bootstrap/node.js"); // 执行 loaders.js 失去函数: `loaders_bootstrapper` MaybeLocal<Function> node_bootstrapper = GetBootstrapper(env, NodeBootstrapperSource(env), node_name); // 下面代码中:LoadersBootstrapperSource() & NodeBootstrapperSource() 是 // 在 /src/node_javascript.h 头文件中申明的,node 源码中并没有它们的具体实现, // 它们的实现代码是在 node 自身构建过程中生成的; // 至于 GetBootstrapper(),它的作用是编译&执行 js 代码,返回执行后果。 if (loaders_bootstrapper.IsEmpty() || node_bootstrapper.IsEmpty()) { return; } Local<Object> global = env->context()->Global(); // ... // 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); /*************************************************************************/ /* 第二步.别离调用这两个启动函数:loaders_bootstrapper、node_bootstrapper ****/ /*************************************************************************/ // Create binding loaders // 基于 GetBinding() 函数模板 创立 get_binding_fn 函数 Local<Function> get_binding_fn = env->NewFunctionTemplate(GetBinding)->GetFunction(env->context()) .ToLocalChecked(); // 基于 GetLinkedBinding() 函数模板 创立 get_linked_binding_fn 函数 Local<Function> get_linked_binding_fn = env->NewFunctionTemplate(GetLinkedBinding)->GetFunction(env->context()) .ToLocalChecked(); // 基于 GetInternalBinding() 函数模板 创立 get_internal_binding_fn 函数 Local<Function> get_internal_binding_fn = env->NewFunctionTemplate(GetInternalBinding)->GetFunction(env->context()) .ToLocalChecked(); // 下面三个函数会作为 调用 loaders_bootstrapper() 时的参数。 Local<Value> loaders_bootstrapper_args[] = { env->process_object(), get_binding_fn, get_linked_binding_fn, get_internal_binding_fn, Boolean::New(env->isolate(), env->options()->debug_options->break_node_first_line) }; // loaders_bootstrapper() 调用后果将保留在这个变量, // 接下来,它将被作为参数传给另一个启动函数:node_bootstrapper() Local<Value> bootstrapped_loaders; // 调用启动函数 loaders_bootstrapper() if (!ExecuteBootstrapper(env, loaders_bootstrapper.ToLocalChecked(), arraysize(loaders_bootstrapper_args), loaders_bootstrapper_args, &bootstrapped_loaders)) { return; } // Bootstrap Node.js Local<Object> bootstrapper = Object::New(env->isolate()); SetupBootstrapObject(env, bootstrapper); Local<Value> bootstrapped_node; Local<Value> node_bootstrapper_args[] = { env->process_object(), bootstrapper, bootstrapped_loaders }; // 调用启动函数 loaders_bootstrapper() if (!ExecuteBootstrapper(env, node_bootstrapper.ToLocalChecked(), arraysize(node_bootstrapper_args), node_bootstrapper_args, &bootstrapped_node)) { return; }}
总结
LoadEnvironment()
次要是调用了两个 启动函数(Bootstrapper)
- loaders_bootstrapper()
- node_bootstrapper()
其中 loaders_bootstrapper() 次要实现了一个简略的模块加载机制名为 NativeModule
,次要用于加载外部模块的,会在 node_bootstrapper() 中用到;
而在 node_bootstrapper() 则加载并执行了用户的 js 文件(也就是通常的 app.js 或 index.js)。
这两个启动函数别离定义在 /lib/internal/bootstrap/loaders.js
和 /lib/internal/bootstrap/node.js
文件中;
接下来的两篇文,会别离对这两个文件进行具体的探索,弄清楚 js 文件加载执行的细节;
By Maslow (wangfugen@126.com), laf.js 作者。
lafyun.com 开源云开发平台,前端变全栈,无需服务端。