欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

簡(jiǎn)單模擬node.js中require的加載機(jī)制

 更新時(shí)間:2016年10月27日 10:49:27   作者:注意_前方高能  
大家都知道Node 采用的模塊化結(jié)構(gòu)是按照 CommonJS 規(guī)范,模塊與文件是一一對(duì)應(yīng)關(guān)系,即加載一個(gè)模塊,實(shí)際上就是加載對(duì)應(yīng)的一個(gè)模塊文件。這篇文章顯示簡(jiǎn)單的介紹了nodejs中require的加載機(jī)制,而后簡(jiǎn)單的模擬require函數(shù),有需要的朋友們下面來(lái)一起看看吧。

一、先了解一下,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)文章

最新評(píng)論