深刻淺出node(2) 模塊機制

這部分主要總結深刻淺出Node.js的第二章  javascript

 一)CommonJsjava

    1.1CommonJs模塊定義node

  二)Node的模塊實現json

    2.1模塊分類後端

    2.2 路徑分析和文件定位瀏覽器

      2.2.1 路徑分析緩存

      2.2.2 文件定位服務器

    2.3 模塊編譯函數

      2.3.1 javascript模塊編譯ui

      2.3.2 exports和module.exports

  三)先後端共用的模塊

    3.1 先後端側重點

    3.2 AMD和CMD

    3.3 兼容多種模塊規範  

一) CommonJs  在CommonJs的官網上寫着這樣一句話 javascript:not just for browsers any more  CommonJs是一種規範,它涵蓋了模塊.二進制.Buffer.文件系統.包管理等,node就是借鑑了CommonJs的Modules規範實現了一套很是易用的模塊系統

  1.1 CommonJs模塊的定義  主要分模塊引用.模塊定義.模塊標識  CommonJs的模塊導入導出機制可使用戶沒必要考慮變量污染等問題

/*模塊引入*/
var
math = require("math"); /*模塊標識 傳遞給require的參數*/ /*模塊定義*/ exports.add = function(a,b) { return a + b; }

二)Node的模塊實現   在Node中對規範進行了必定的取捨,也增長了必定自身須要的特性 node中引入模塊主要分爲3個步驟

  1. 路徑分析
  2. 文件定位
  3. 編譯執行

  2.1 Node中的模塊分類  在node中模塊分爲兩類 Node提供的模塊,核心模塊. 用戶編寫的模塊,文件模塊

  • 核心模塊 在node的源代碼編譯的過程當中被編譯進了二進制執行文件,在node進程啓動的時候,部分的核心模塊被直接加載到內存,因此引用這部分模塊不須要文件的定位和編譯執行,而且在路徑分析中優先判斷,因此加載速度最快
  • 文件模塊  運行時動態的加載,須要完成的路徑解析,文件定位,編譯執行過程,加載速度相對較慢    

不管是核心仍是文件模塊 Node都會採用緩存優先的策略,不一樣於瀏覽器中緩存的是文件,Node中緩存的是編譯和執行以後的對象

  2.2 路徑分析和文件定位

    2.2.1 路徑分析 node中根據require()中傳入的標識符,來進行模塊的查找和定位,對不一樣類型的標識符查找定位的方式會有一些區別  標識符只要分爲下面幾類

  1. 核心模塊(核心模塊的優先級的優先級僅次於緩存加載,在Node的源代碼的編譯過程當中已經被編譯成了二進制的代碼,加載過程最快 沒法加載與核心模塊相同標識符的自定義模塊,只能經過其餘的方式加載與核心模塊相同標識符的自定義模塊)
  2. 絕對路徑或者相對路徑的文件模塊(經過將相對路徑和絕對路徑轉換成真實路徑,而且以真實路徑做爲索引,將編譯後的結果放到緩存中,因爲指明瞭確切的文件位置,因此其加載速度慢於核心模塊)
  3. 非路徑形式的文件模塊,一般爲自定義模塊(當前文件目錄下的node_modules  父目錄下的node_modules 父目錄的父目錄下的node_modules  沿路徑向上逐級遞歸,直到根目錄的node_modules   很像原型鏈的查找 因此自定義模塊的查找速度最慢)       

    2.2.2 文件定位

  • 文件的擴展名分析 CommonJs中容許在標識符中不包含擴展名,這種狀況下Node會按照.js,.node,.json的次序補足擴展名 在require的時候,是同步阻塞的判斷文件是否存在的,此時加入你肯定需求的文件的擴展名字是.node,.json,在require的時候補足擴展名,能加快一下訪問速度
  • 目錄分析和包  若是你經過require()的標示符查找到一個目錄,Node會將這個目錄當作包處理 Node會在當前的目錄下查找package.json文件,經過JSON.parse()解析出包描述對象,從中讀取出main屬性執行的文件進行定位,若是該文件不存在擴展名,則進入擴展名解析的步驟 若是main執行的文件錯誤或者不存在package.json文件,Node會將index當作默認的擴展名,而後依次的查找index.js,index.json,index.json
  • 若是在經過上面的方式仍然沒有定位到相應的文件或者模塊,則上升到下一個模塊路徑進行查找    

  2.3 模塊編譯  在node中文件模塊都是對象.相似下面的定義 在定位到具體的文件後,node會建立一個模塊對象,而後載入和編譯

  

function Module(id,parent) {
    this.id = id;
    this.exports = {};
    this.parent = parent;
    if(parent && parent.children) {
        parent.children.push(this);
    }
    this.filename = null;
    this.loaded = false;
    this.children = [];
}

  在引入模塊的時候,對不一樣擴展名的文件node的載入方式也不一樣

  • .js 經過fs模塊同步讀取文件後編譯執行
  • .node C++編寫的擴展文件,經過dlopen()方法加載最後編譯生成的文件  (.node模塊是經過C/C++編譯後生成的,因此只有加載和執行的過程,C/C++模塊的優點是執行效率更高但相對於javascript模塊來講開發門檻更高)
  • .json 經過fs模塊同步讀取文件後,用JSON.parse()解析返回結果
  • 其他擴展名 都會當作.js文件載入

  2.3.1 javascript模塊編譯 

     在編譯的過程當中,node會對獲取到的內容進行封裝 相似於下面的樣子

(function(exports,require,module,__filename,__dirname){
    /**
     * 你的js代碼
     */
})

這樣模塊之間就進行了做用域的隔離 而後經過vm原生模塊的runInThisContext()方法執行返回一個function對象 而後將以前的模塊對象的exports,require()方法,module,文件路徑等信息傳入給函數執行,執行以後將exports屬性返回給調用方,而且將編譯後的結果根據路徑索引緩存到Module._cache上

  exports和module.exports 

    簡單理解就是exports是module.exports的引用 具體看 exports和module.exports的區別

三)先後端共用的模塊

  3.1 先後端側重點

  • 瀏覽器端的javascript須要從同一個服務器分發到客戶端,受限於帶寬,讀取速度慢
  • 服務器端的javascript是相同的代碼須要屢次的執行,受限於CPU和內存,後端代碼直接從硬盤中讀取加載速度快
  • node中模塊的引入是同步的,但瀏覽器中同步的方式不可行    

  3.2 AMD和CMD規範

  • AMD模塊定義的方式以下,它是CommonJs規範的一個延伸
define(id?,dependencies?,factory)

這裏的factory就是實際代碼的內容  在AMD中須要顯示的定義一個模塊,在node中這個過程是隱式包裝

  • CMD CMD在引入的時候支持動態引入  

  3.3 兼容多種模塊規範

;(function(name,definition){
    var hasDefine = typeof define === 'define',
        hasExports = typeof module !== 'undefined' && module.exports;
    if(hasDefine) {
        //AMD CMD
        define(definition);
    } else if(hasExports){
        //node環境
        module.exports = definition()
    } else {
        //掛在在window
        this[name] = definition();
    }
})(name,function(){
    var obj = {};
    retuen obj;
});
相關文章
相關標籤/搜索