亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

淺析node.js的模塊加載機制

2024-05-06 16:44:35
字體:
來源:轉載
供稿:網友

在node.js中,模塊使用CommonJS規范,一個文件是一個模塊

node.js中的模塊可分為三類

  1. 內部模塊 - node.js提供的模塊如 fs,http,path等
  2. 自定模塊 - 我們自己寫的模塊
  3. 第三方模塊 - 通過npm安裝的模塊

node.js提供了大量的模塊供我們使用,比如 想解析一個文件的路徑,可以使用path模塊下的相應方法實現:

const path = require('path');//返回目標文件的絕對路徑console.log(path.resolve('./1.txt'));

運行結果:

/Users/cuiyue/workspace/test/1.txt

使用require引入相應的模塊,即可使用。

__dirname和__filename

node.js的每個模塊都有這兩個參數,它們都是一個絕對路徑的地址,區別是__filename存放了從根目錄到當前文件名的路徑,__dirname只存放從根目錄到模塊的所在目錄:

console.log(__dirname);console.log(__filename);

運行結果:

/Users/cuiyue/workspace/test
/Users/cuiyue/workspace/test/module.js

vm模塊

vm模塊是node.js提供在V8虛擬機中編譯和運行的工具,node.js中的模塊內部實現就是通過此模塊完成。

說說vm的基本用法。

在js環境中有一個eval函數,它可以運行js的代碼字符串,比如:

eval('console.log("Hello javascript.")'); //輸出Hello javascript.

可以看到,eval函數的參數是一段字符串,它可以運行字符串形式的js代碼,但它可以使用上下文環境中的變量:

var num=100;eval('console.log(num)'); //輸出100

以上是可以正確訪問num的值。

vm模塊提供了方法創建一個安全的沙箱,在指定的上下文環境中運行代碼,不受外界干擾。

const vm = require('vm');var num = 100;vm.runInThisContext('console.log(num)');

運行結果:

console.log(num)
            ^
ReferenceError: num is not defined

可以看到代碼報錯了,說明在vm創建了指定的上下文環境中,拿不到外界的參量。

CommonJS規范

在以前,由于javascript的歷史原因導致它的模塊機制很差,由于這些缺點使得javascript不太善于開發大型應用,于是提出了CommonJS規范以彌補javascript的不足。

CommonJS規范主要分為三塊內容:模塊導入導出、模塊定義、模塊標識。

模塊導入導出

CommonJS中使用require()函數進行模塊的引入。

const mymodule = require('mymodule');

使用exports導出模塊

module.exports = {  name: 'Tom'};

引用的名稱可以不帶路徑,若不帶路徑表示引入的是node提供的模塊或是npm安裝的第三方模塊(node_modules)

模塊定義

module對象:在每一個模塊中,module對象代表該模塊自身。

export屬性:module對象的一個屬性,它向外提供接口。

模塊標識

模塊標識指的是傳遞給require方法的參數,必須是符合小駝峰命名的字符串,或者以 .、..、開頭的相對路徑,或者絕對路徑。

node中模塊解析流程

  1. 首先接收參數,把傳入的模塊名稱解析成絕對路徑
  2. 若沒有后綴名稱,依次拼接.js .json .node嘗試加載,仍到不到模塊則報錯
  3. 取得正確的路徑后判斷緩存中是否存在此模塊,若有則取出
  4. 若緩存中不存在則加載此文件,在外包裹一層閉包并執行它

以上為大致流程,下面嘗試著寫一下模塊。

代碼的基本結構:

/** * Module類,用于處理模塊加載 */function Module() {}//模塊的緩存Module._cacheModule = {};//不同擴展名的加載策略Module._extensions = {};//根據moduleId解析絕對路徑,Module._resolveFileName = function(moduleId) {};//入口函數function req(moduleId) {}

附上全部代碼:

const path = require('path');const fs = require('fs');const vm = require('vm');/** * Module類,用于處理模塊加載 */function Module(file) { this.id = file; //當前模塊的id,它使用完整的絕對路徑標識,因此是唯一的 this.exports = {}; //導出 this.loaded = false; //模塊是否已加載完畢}//模塊的緩存Module._cacheModule = {};Module._wrapper = ['(function(exports,require,module,__dirname,__filename){', '});'];//不同擴展名的加載策略Module._extensions = { '.js': function(currentModule) {  let js = fs.readFileSync(currentModule.id, 'utf8'); //讀取出js文件內容  let fn = Module._wrapper[0] + js + Module._wrapper[1];  vm.runInThisContext(fn).call(   currentModule.exports,   currentModule.exports,   req,   currentModule,   path.dirname(currentModule.id),   currentModule.id);  return currentModule.exports; }, '.json': function(currentModule) {  let json = fs.readFileSync(currentModule.id, 'utf8');  return JSON.parse(json); //轉換為JSON對象返回 }, '.node': ''};//加載模塊(實例方法)Module.prototype.load = function(file) { let extname = path.extname(file); //獲取后綴名 return Module._extensions[extname](this);};//根據moduleId解析絕對路徑,Module._resolveFileName = function(moduleId) { let p = path.resolve(moduleId); if (!path.extname(moduleId)) { //傳入的模塊沒有后綴  let arr = Object.keys(Module._extensions);  //循環讀取不同擴展名的文件  for (var i = 0; i < arr.length; i++) {   let file = p + arr[i]; //拼接上后綴名成為一個完整的路徑   try {    fs.accessSync(file);    return file; //若此文件存在返回它   } catch (e) {    console.log(e);   }  } } else {  return p; }};function req(moduleId) { let file = Module._resolveFileName(moduleId); if (Module._cacheModule[file]) { //若緩存中存在此模塊  return Module._cacheModule[file]; } else {  let module = new Module(file);  module.exports = module.load(file);  return module.exports; }}console.log(req('./a.js')());

a.js的文件內容:

module.exports = function() { console.log('This message from a.js'); console.log(__dirname); console.log(__filename);}

最終運行結果:

This message from a.js
/Users/cuiyue/workspace/test
/Users/cuiyue/workspace/test/a.js

重要代碼說明

_resolveFileName

_resolveFileName方法的主要作用是把傳入的模塊解析成絕對路徑,這樣才可以進行下一步,根據完整的路徑加載模塊。

因此要進行判斷,如果傳入的模塊不存在,則要報錯;如果傳入的模塊已經有擴展名了,就不要拼接了;若沒有擴展名,依次以.js .json .node的順序拼接成完成的模塊進行加載。

_extensions

此對象中封裝了加載不同類型模塊的處理方法,其中若是.json類型則使用fs讀取文件直接轉換成JSON對象并返回。

若是.js文件則讀取后,拼接閉包,將exports,require,module,__dirname,__filename五大參數拼接好,使用vm模塊的沙箱機制運行,得到的結果放入module.exports返回。

總結

以上就是node.js的模塊加載的簡單邏輯,實際上node.js的源碼遠遠比上面的代碼復雜,光是處理模塊路徑、判斷合法等操作就寫了N行。而且我這里沒有寫緩存以及其它的復雜邏輯,但核心差不多就是這些,核心的核心就是用fs.readFileSync讀取js文件,把內容拼接到一個大大的閉包中,這也解釋了為什么我們自己寫的所有node模塊中都會有require方法,exports導出,以及__dirname和__filename參數。

了解了node.js的模塊加載邏輯,在以后寫node.js就更可避免一些誤解,寫出精細的代碼。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲xxxx妇黄裸体| 久久精品国产一区二区电影| 欧美久久久精品| 国产精品高潮在线| 色综合影院在线| 欧美国产日产韩国视频| 日日骚av一区| 亚洲欧美中文日韩在线| 狠狠色狠狠色综合日日小说| 色婷婷av一区二区三区在线观看| 色av吧综合网| 久久精品亚洲热| 欧美性视频在线| 91精品视频在线看| 亚洲天堂男人的天堂| 国外色69视频在线观看| 国产精品亚洲аv天堂网| 亚洲欧美国产一区二区三区| 精品亚洲一区二区三区在线观看| 8090成年在线看片午夜| 国产精品欧美在线| 日韩精品久久久久久福利| 精品自拍视频在线观看| 精品国产一区二区三区四区在线观看| 91精品国产高清自在线| 青青久久av北条麻妃海外网| 欧美激情xxxx性bbbb| 亚洲天堂av在线免费观看| 国产精品丝袜久久久久久不卡| 欧美性猛交xxxx免费看| 91视频免费网站| 国产在线观看精品一区二区三区| 91精品国产综合久久香蕉922| 自拍偷拍亚洲精品| 中文欧美日本在线资源| 欧美成人免费网| 国产精品777| 精品久久久久久| 自拍偷拍亚洲欧美| 国产精品99久久久久久www| 欧美夫妻性生活xx| 国产精品青草久久久久福利99| 91免费电影网站| 亚洲v日韩v综合v精品v| 久久精品视频在线播放| 国产精品国产三级国产专播精品人| 亚洲精品国产精品国产自| 久久久国产精彩视频美女艺术照福利| 亚洲精品中文字幕有码专区| 亚洲人成五月天| 欧美电影免费观看| 亚洲 日韩 国产第一| 91精品国产色综合| 国产精品久久久久久久久久东京| 亚洲一区二区三区乱码aⅴ蜜桃女| 日韩成人在线视频观看| 欧美日韩国产91| 日韩一区二区精品视频| 国产亚洲成av人片在线观看桃| 91精品91久久久久久| 激情av一区二区| 国产日韩av高清| 亚洲精品福利免费在线观看| 成人免费高清完整版在线观看| 久久久999国产精品| 亚洲三级免费看| 国产一区二区三区直播精品电影| 911国产网站尤物在线观看| 国产精品视频公开费视频| 国产精品老女人视频| 欧美做爰性生交视频| 国产精品久久久久久久美男| 亚洲japanese制服美女| 国产精品ⅴa在线观看h| 久久最新资源网| 亚洲精品久久久久久久久久久久久| 成人欧美一区二区三区黑人| 欧美日产国产成人免费图片| 97久久超碰福利国产精品…| 亚洲国产日韩一区| 欧美最顶级丰满的aⅴ艳星| 91精品久久久久久久久中文字幕| 少妇高潮久久77777| 日韩精品亚洲精品| 一区二区亚洲欧洲国产日韩| 欧美视频中文在线看| 国产成人精品午夜| 怡红院精品视频| 国色天香2019中文字幕在线观看| 国产v综合v亚洲欧美久久| 欧美不卡视频一区发布| 欧美小视频在线观看| 亚洲跨种族黑人xxx| 日韩成人激情在线| 亚洲精品小视频| 国产成人精品免费久久久久| 久久久久久国产三级电影| 亚洲精品日韩激情在线电影| 亚洲国产高清自拍| 日韩av电影手机在线| 欧美一区二粉嫩精品国产一线天| 久久夜色精品国产| 尤物yw午夜国产精品视频| 国产精品高潮呻吟久久av无限| 91网站在线免费观看| 国产成人精品在线观看| 8090理伦午夜在线电影| 亚洲第一区在线| 久久亚洲春色中文字幕| 亚洲国产天堂网精品网站| 亚洲成人精品av| 国产精品中文字幕在线观看| 欧美日韩第一页| 欧美极度另类性三渗透| 亚洲午夜未满十八勿入免费观看全集| 亚洲成人久久网| 欧美精品成人91久久久久久久| 欧美亚洲另类在线| 亚洲老板91色精品久久| 亚洲视频一区二区三区| 国产成人免费91av在线| 日韩精品视频免费在线观看| 亚洲精品永久免费精品| 日韩中文字幕久久| 国产亚洲精品综合一区91| 久久69精品久久久久久久电影好| 欧美大全免费观看电视剧大泉洋| 欧美成人精品一区二区| 国产精品久久久久久久久久新婚| 日韩av影视综合网| 色av中文字幕一区| 国产成人av在线| 日韩风俗一区 二区| 亚洲成人教育av| 国产精品久久久久久久久| 欧美色图在线视频| 欧美专区日韩视频| 国产精品视频在线播放| 亚洲一区二区三区乱码aⅴ蜜桃女| 久久久久久午夜| 日韩hd视频在线观看| 久久精品成人动漫| 欧美亚洲午夜视频在线观看| 91综合免费在线| 亚洲综合精品一区二区| 久久久久久有精品国产| 91精品国产91久久久久久久久| 性色av一区二区三区| 欧美在线视频一区| 色悠久久久久综合先锋影音下载| 一区二区三区天堂av| 色老头一区二区三区在线观看| 热久久免费国产视频| 久久久精品国产网站| 庆余年2免费日韩剧观看大牛| 国产美女精品视频免费观看| 国产成人一区二区三区小说| 亚洲小视频在线| 国产在线观看不卡| 国产精品色午夜在线观看| 一区二区成人av| 欧美成人中文字幕| 日韩美女在线观看一区| 国产精品日韩在线观看|