title: Node.js 原始碼分析 - 加載 js 檔案
date: 2018-11-30 21:04:49
tags:
- Node.js
- Node.js 原始碼分析
- 原始碼分析
categories:
- Node.js 原始碼分析
此文最初于四年前發布在個人站上的,現遷移至此重發,原鏈接:https://laogen.site/nodejs/nodejs-src/bootstrap-js/
《Node.js 原始碼分析》 系列目錄頁:https://laogen.site/nodejs/nodejs-src/index/
提出問題
了解 js 檔案加載前的準備作業
在《從 main 函式開始》這篇中說到了 LoadEnvironment() 函式負責加載 js 代碼,但并沒有繼續說明加載細節,
這篇從 LoadEnvironment() 開始探究 js 代碼加載的詳細程序,
LoadEnvironment()
LoadEnvironment() 的邏輯分兩部分:
- 加載并執行兩個 js 檔案:
loaders.jsnode.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 檔案加載執行的細節;
Maslow ([email protected]), laf.js 作者,
lafyun.com 開源云開發平臺,前端變全堆疊,無需服務端,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/431435.html
標籤:JavaScript
上一篇:單元測驗 - 測驗場景記錄
下一篇:GoJS 使用筆記
