摘要:提起中的模塊,就會想到用去加在引用那個模塊。看了不少博客,加載機制明白了,腦子里總是稀里糊涂的知道會每個文件會被文件的源碼包裹,自然也就有文件中的命令了。于是想寫寫記錄自己的整個過程。這就是幾個的關系。
提起nodejs中的模塊,就會想到用require去加在引用那個模塊。看了不少博客,加載機制明白了,腦子里總是稀里糊涂的知道會每個文件會被"(function (exports, require, module, __filename, __dirname) {",
// 文件的源碼
"n});"包裹,自然也就有文件中的require命令了。前幾天看了模塊的源碼 https://github.com/nodejs/nod...
module.js源碼的前幾行
const NativeModule = require("native_module"); const util = require("util"); const internalModule = require("internal/module"); const vm = require("vm"); const assert = require("assert").ok; const fs = require("fs"); const internalFS = require("internal/fs");
一上來就懵了,module.js不就是為了實現require的嗎?為什么一上來就用require去引用其他模塊,從而陷入死循環。在一些技術網站提問https://cnodejs.org/topic/58b... 雖然還不是很明白,但得到了一些思路,然后又開始重新看源碼,并動手調試,總算想清楚了。于是想寫寫記錄自己的整個過程。
一、module.js前幾行的require從哪里來的
寫了兩個js文件,a.js
const b = require("./b.js");
b.js
exports.done = false;
node 執行a.js
首先node啟動時會先執行第一個js文件https://github.com/nodejs/nod...
這個文件中會定義module.js中第一行的NativeModule。可以看到NativeModule的定義
function NativeModule(id) { this.filename = `${id}.js`; this.id = id; this.exports = {}; this.loaded = false; this.loading = false;
}
從入口函數startup中可以看到
const Module = NativeModule.require("module");也就是說會去加載module.js模塊。
在require函數中
NativeModule.require = function(id) { if (id === "native_module") { return NativeModule; } /..../ const nativeModule = new NativeModule(id);新建NativeModule對象 nativeModule.cache(); nativeModule.compile(); //主要步驟 return nativeModule.exports;
};
在compile中
NativeModule.prototype.compile = function() { var source = NativeModule.getSource(this.id); source = NativeModule.wrap(source); this.loading = true; try { const fn = runInThisContext(source, { filename: this.filename, lineOffset: 0, displayErrors: true }); fn(this.exports, NativeModule.require, this, this.filename); this.loaded = true; } finally { this.loading = false; }
};
wrap會進行文件的包裹
NativeModule.wrap = function(script) { return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; }; NativeModule.wrapper = [ "(function (exports, require, module, __filename, __dirname) { ", " });" ];
這里的require是NativeModule.require
接下來就會執行Module.runMain函數,從而進入module.js中,所以module
.js中開始的require是NativeModule.require,并不矛盾。
二、a.js的執行情況
執行a.js時則會通過bootstrap_node.js的runMain函數進入module.js
Module.runMain = function() { // Load the main module--the command line argument. Module._load(process.argv[1], null, true); // Handle any nextTicks added in the first tick of the program process._tickCallback(); };調用Module._load函數,process.argv[1]為a.js
Module.runMain->Module._load->tryModuleLoad->module.load->Module._extensions[".js"]->module._compile
在module._compile中
var wrapper = Module.wrap(content);這個時候才調用NativeModule的wrap函數對a.js就行包裹
接下來
var require = internalModule.makeRequireFunction.call(this);會通過 https://github.com/nodejs/node/blob/master/lib/internal/module.js中的makeRequireFunction函數創造一個require函數, function require(path) { try { exports.requireDepth += 1; return self.require(path); } finally { exports.requireDepth -= 1; }
}
call.(this)將指針指向module,從而a.js包裹的頭部中require就是makeRequireFunction返回的require,
self.require(path);則會調用用Module.prototype.require
Module.prototype.require = function(path) { return Module._load(path, this, /* isMain */ false); }; require則會調用 Module._load去加載其他模塊。
這就是幾個require的關系。
新人第一次寫,如有錯誤,還請糾正。
參考:
https://github.com/nodejs/nod...
https://github.com/nodejs/nod...
https://github.com/nodejs/nod...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81946.html
摘要:先把當成文件,依次查找當前目錄下的,找到了,就返回該文件,不再繼續執行。那么關于正確的結論是在中使用是跟的效果相同,不會因為啟動腳本的目錄不一樣而改變,在其他情況下跟效果相同,是相對于啟動腳本所在目錄的路徑。 起因 原文收錄在我的 GitHub博客 (https://github.com/jawil/blog) ,喜歡的可以關注最新動態,大家一起多交流學習,共同進步,以學習者的身份寫博...
摘要:先把當成文件,依次查找當前目錄下的,找到了,就返回該文件,不再繼續執行。那么關于正確的結論是在中使用是跟的效果相同,不會因為啟動腳本的目錄不一樣而改變,在其他情況下跟效果相同,是相對于啟動腳本所在目錄的路徑。 起因 原文收錄在我的 GitHub博客 (https://github.com/jawil/blog) ,喜歡的可以關注最新動態,大家一起多交流學習,共同進步,以學習者的身份寫博...
摘要:之后需要對中的結果數據做分析,并且制作圖表寫周報發給老大。輪到我值班的時候就用寫了一個腳本自動處理中的數據,并且將數據再寫入文件。腳本目的讀取文件,分析中的數據,并且將結果寫入中。 背景 因為 Team 本身工作性質的問題,平時需要值班。值班數據可以導出為本地的Excel文件。之后需要對Excel中的結果數據做分析,并且制作圖表寫周報發給老大。 對于我這種對word都玩不轉的人,別說用...
摘要:以異步方式事件隊列為標準,基本每一套與網絡相關的都會設計成異步的。在這種情況下,同步的網絡請求比異步的請求會更加合適,代碼更加清晰,邏輯更簡單,而且對代碼效率要求不高。如下,便是簡化后的同步請求,文本替換的代碼。 node.js 以異步方式、事件隊列為標準,基本每一套與網絡、IO 相關的 API 都會設計成異步的。 如,一段很平常的請求代碼,用 node.js 只能用異步方式。 con...
閱讀 1848·2021-11-22 15:24
閱讀 1307·2021-11-12 10:36
閱讀 3194·2021-09-28 09:36
閱讀 1837·2021-09-02 15:15
閱讀 2745·2019-08-30 15:54
閱讀 2391·2019-08-30 11:02
閱讀 2392·2019-08-29 13:52
閱讀 3539·2019-08-26 11:53