簡(jiǎn)單模擬node.js中require的加載機(jī)制
一、先了解一下,nodejs中require的加載機(jī)制
1、require的加載文件順序
require 加載文件時(shí)可以省略擴(kuò)展名:
require('./module');
// 此時(shí)文件按 JS 文件執(zhí)行
require('./module.js');
// 此時(shí)文件按 JSON 文件解析
require('./module.json');
// 此時(shí)文件預(yù)編譯好的 C++ 模塊執(zhí)行
require('./module.node');
// 載入目錄module目錄中的 package.json 中main指向的文件
require('./module/default.js');
// 載入目錄module 中的index.js文件
通過(guò) ./ 或 ../ 開(kāi)頭:則按照相對(duì)路徑從當(dāng)前文件所在文件夾開(kāi)始尋找模塊;
require('../file.js');
=> 上級(jí)目錄下找 file.js 文件
通過(guò) / 開(kāi)頭:則以系統(tǒng)根目錄開(kāi)始尋找模塊;
require('/Users/iceStone/Documents/file.js');
=> 以絕對(duì)路徑的方式找,沒(méi)有任何異議
如果參數(shù)字符串不以“./“ 或 ”/“ 開(kāi)頭,則表示加載的是一個(gè)默認(rèn)提供的核心模塊(位于 Node 的系統(tǒng)安裝目錄中):
require('fs');
=> 加載核心模塊中的文件系統(tǒng)模塊
或者從當(dāng)前目錄向上搜索 node_modules 目錄中的文件:
require('my_module');
=> 各級(jí) node_modules 文件夾中搜索 my_module.js 文件;
如果 require 傳入的是一個(gè)目錄的路徑,會(huì)自動(dòng)查看該目錄的 package.json 文件,然后加載 main 字段指定的入口文件
如果package.json文件沒(méi)有main字段,或者根本就沒(méi)有package.json文件,則默認(rèn)找目錄下的 index.js 文件作為模塊:
require('./calcuator');
=> 當(dāng)前目錄下找 calculator 目錄中的 index.js 文件
2、require緩存
第一次加載某個(gè)模塊時(shí),Node 會(huì)緩存該模塊。以后再加載該模塊,就直接從緩存取出該模塊的 module.exports 屬性(不會(huì)再次執(zhí)行該模塊)
如果需要多次執(zhí)行模塊中的代碼,一般可以讓模塊暴露行為(函數(shù)),模塊的緩存可以通過(guò) require.cache 拿到,同樣也可以刪除
3、所有代碼都運(yùn)行在模塊作用域,不會(huì)污染全局作用域。
二、模擬require函數(shù)
require的加載內(nèi)部比較復(fù)雜,下面讓我們進(jìn)行簡(jiǎn)單的模擬加載
require的簡(jiǎn)單實(shí)現(xiàn)機(jī)制為:
將傳入的模塊id通過(guò)加載規(guī)則找到對(duì)應(yīng)的模塊文件
讀取這個(gè)文件里面的代碼
通過(guò)拼接方式為該段代碼構(gòu)建私有空間
執(zhí)行該代碼
拿到module.exports 返回
nodejs_require.js // [require函數(shù)模擬] "use strict" function $require(id) { //1、先查看模塊是否存在,如果不存在則拋出 Can't found file //2、如果存在,就讀取代碼 const fs = require('fs'); const path = require('path'); // 文件名 let filename = id; //查看是否是絕對(duì)路徑 if (!path.isAbsolute(filename)) { filename = path.join(__dirname, id); } // 文件目錄 let dirname = path.dirname(filename); //模擬require的緩存機(jī)制 $require.cache = $require.cache || {}; if($require.cache[filename]){ return $require.cache[filename].exports; } // 讀取模塊代碼 let code=""; try { code = fs.readFileSync(filename,'utf-8'); // 阻塞讀取文件,不會(huì)放入事件隊(duì)列 } catch (error) { console.log(" [*]can't found file! "); throw error; } // console.log(code); // 3、執(zhí)行代碼,所要執(zhí)行的代碼,需要營(yíng)造一個(gè)獨(dú)立的空間 // 定義一個(gè)數(shù)據(jù)容器,用容器去裝模塊導(dǎo)出的成員 let _module = { // 每個(gè)js模塊都會(huì)有一個(gè)全局的module變量 id:'.', exports:{}, parent:module, filename:filename }; let _exports = _module.exports; // 營(yíng)造一個(gè)獨(dú)立空間 code = `(function($require,module,_exports,__dirname,__filename){ $[code] })($require,_module,_exports,dirname,filename)`; // 執(zhí)行代碼 eval(code); // 緩存 $require.cache[filename] = _module; // 返回結(jié)果 return _module.exports; } setInterval(()=>{ const rr = $require("./test.js"); console.log(rr); },1000);
上面的模塊測(cè)試使用的兩個(gè)模塊
//test.js const date = $require('./date.js'); console.log(module); module.exports = date; //date.js module.exports = new Date();
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
相關(guān)文章
nodejs實(shí)現(xiàn)范圍請(qǐng)求的實(shí)現(xiàn)代碼
這篇文章主要介紹了nodejs實(shí)現(xiàn)范圍請(qǐng)求的實(shí)現(xiàn)代碼,使服務(wù)器支持范圍請(qǐng)求,允許客戶端只請(qǐng)求文檔的一部分,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-10-10nodejs做個(gè)爬蟲(chóng)爬取騰訊動(dòng)漫內(nèi)容簡(jiǎn)單實(shí)現(xiàn)
這篇文章主要為大家介紹了nodejs做個(gè)爬蟲(chóng)爬取騰訊動(dòng)漫內(nèi)容簡(jiǎn)單實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07npm?install安裝失敗報(bào)錯(cuò):The?operation?was?rejected?by?your?
這篇文章主要給大家介紹了關(guān)于npm?install安裝失敗報(bào)錯(cuò):The?operation?was?rejected?by?your?operating?system的相關(guān)資料,文中給出了多種解決方法供大家參考學(xué)習(xí),需要的朋友可以參考下2023-04-04NodeJS?Express使用ORM模型訪問(wèn)關(guān)系型數(shù)據(jù)庫(kù)流程詳解
這篇文章主要介紹了NodeJS?Express使用ORM模型訪問(wèn)關(guān)系型數(shù)據(jù)庫(kù)流程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01nodejs部署到騰訊云服務(wù)器的實(shí)現(xiàn)(寶塔面板linux系統(tǒng))
本文主要介紹了nodejs部署到騰訊云服務(wù)器的實(shí)現(xiàn)(寶塔面板linux系統(tǒng)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06node.js連接MongoDB數(shù)據(jù)庫(kù)的2種方法教程
這幾天一直在學(xué)習(xí)mongdb的基礎(chǔ)知識(shí),跟著網(wǎng)上大神的腳步(代碼)去模擬連接mongodb數(shù)據(jù)庫(kù),下面這篇文章就給大家總結(jié)介紹了node.js連接MongoDB數(shù)據(jù)庫(kù)的2種方法教程,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-05-05快速掌握Node.js環(huán)境的安裝與運(yùn)行方法
這篇文章主要介紹了Node.js環(huán)境的安裝與運(yùn)行方法,Node是基于Google Chrome V8引擎的JavaScript解釋器,需要的朋友可以參考下2016-02-02用node-webkit把web應(yīng)用打包成桌面應(yīng)用(windows環(huán)境)
這篇文章主要介紹了windows環(huán)境下用node-webkit把web應(yīng)用打包成桌面應(yīng)用的教程,需要的朋友可以參考下2018-02-02使用socket.io實(shí)現(xiàn)簡(jiǎn)單聊天室案例
這篇文章主要介紹了使用socket.io實(shí)現(xiàn)簡(jiǎn)單聊天室案例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01