起源
javascript當初被設計出來用於瀏覽器,js的能力大小取決於執行環境對於api的支援能力。在web的發展中,瀏覽器中出現了更多標準api,但是後端javascript規範卻遠遠落後。對於javscsript語言而言, 它薄弱環節是缺少規範:
- 沒有模組系統
- 標準庫少
- 沒有標準介面
- 缺乏包管理系統
commonJS規範的提出,主要是彌補了js沒有標準的缺陷,以具備開發大型應用的基礎能力,而不是停留在小型指令碼的處境。在發展中,commonJS的成長中,規範涵蓋了模組、二進位制、buffer、字符集編碼、i/o流、程式環境、檔案系統、套接字、單元測試、tcp/ip、包管理等。
commonJS規範
- 模組引用:使用
require()
引用一個模組 - 模組定義:在模組中,上下文提供require()引入外部模組,匯入相應功能。上下文提供了export()方法匯出當前模組的方法或者變數。並且這是唯一到匯出出口。模組中還存在一個module物件。他代表模組自身,export是module的屬性。在node中,一個檔案就是一個模組
- 模組標示:模組標示就是傳遞給require()的引數,內部模組可以是駝峰字串,自己寫的模組可以使相對路徑和絕對路徑,可以忽略字尾名。
Node的模組實現
先上圖:
首先判斷引用的模組是否是核心模組。如果是,則直接使用。因為核心模組在node啟動時就已經載入進了記憶體中。如果非核心模組,則為檔案模組。引用檔案模組首先會查詢快取中是否存在,如果存在就直接執行。若不存在,則會對require中傳入的識別符號進行地址補全,轉化成絕對路徑,再依次新增.js/.node/.json進行讀取嘗試。如果目標檔案為json,會通過JSON.parse()
轉化後返回。
如果目標檔案為.node,會通過dlopen()方法進行載入。
如果目標檔案為.js,先在讀取的檔案字串首尾依次拼接(function(){
和})
,目的是解析執行時為模組程式碼新增一個封閉作用域。然後呼叫vm原生模組的runInThisContext()
方法執行。返回一個具體的function物件。不會汙染全域性。最後call()執行。