2011-07-13 219 views
42

我很好奇在使用它之後是否有任何好的方式卸載模塊。我有一些情況需要使用帶有大量代碼的模塊,但很少使用(比如說作爲管理工具),但我不願意使用它們,因爲之後它們大概會浪費內存,可能會更好在別處使用。有沒有什麼辦法可以將它們卸載,無論是明確的還是讓系統在未使用一段時間的時候這樣做?卸載代碼/模塊

回答

64

是的,這是可以直接訪問的模塊緩存:

var name = require.resolve('moduleName'); 
delete require.cache[name]; 

需要注意的是,如果你的代碼執行到任何被你想擺脫這些模塊暴露一個參考,它不會清理乾淨。

(順便說一句:下面的表面,require.resolverequire.cache只是代理到Module._resolveFilenameModule._cache分別與Module爲核心模塊加載,即require('module')

+8

這不是一個完整的答案。有些需要加載一個index.js文件,然後加載庫的真正肉。 作爲一個例子,嘗試 require('async') 這加載「... async/lib/async.js」,但也加載「..async/index.js」,你可以在require .cache。 index.js是async.js的父項。所以可能取消註冊,但可能需要遞歸功能來刪除多個模塊。 –

+4

只需做'for(var key in Object.keys(require.cache)){delete require.cache [key];}'。 – Tower

+3

@Tower,這將卸載所有模塊。嘗試檢查'module.parent' - 或者其他東西 - 可能會更好,只卸載要卸載的模塊。例如,'util'和'fs'可能不應該被卸載。 –

3

你可以做這樣的事情「卸載「節點模塊:

/** 
* Deletes a node module and all associated children 
* from node require cache 
* @param {string} moduleName The name of the module or 
*       absolute/relative path to it 
*/ 
function deleteModule(moduleName) { 
    var solvedName = require.resolve(moduleName), 
    nodeModule = require.cache[solvedName]; 
    if (nodeModule) { 
    for (var i = 0; i < nodeModule.children.length; i++) { 
     var child = nodeModule.children[i]; 
     deleteModule(child.filename); 
    } 
    delete require.cache[solvedName]; 
    } 
} 

」卸載「一個節點模塊意味着您正在從節點require cache中」刪除「它的條目。上面的代碼片段從緩存和所有關聯的模塊(子模塊)中過渡地刪除了一個節點模塊。

在我的情況下,我需要「index.js」,同時需要「/lib/.js」。我想測試「index.js」的初始化(因此在那裏是唯一需要的其他模塊是/lib/.js)。從緩存中刪除「index.js」是不夠的,因爲緩存保持對「/lib/.js」的單獨引用並且導致模塊「/lib/.js」不再從其文件中加載。

上面的代碼可能肯定會從緩存中刪除此模塊依賴的其他模塊(這實際上是我想要的,但是您可能不希望爲其他模塊(如「fs」,「path」或甚至「下劃線」)執行此操作。 )。

您可以始終將此方法擴展爲接受您不想刪除的模塊列表或可應用於已解析模塊「路徑」的過濾器。可以這樣說:不要刪除核心節點模塊(核心節點模塊名稱列表可作爲npm包使用:https://www.npmjs.com/package/node-core-module-names),也不要刪除node_modules等下的任何包。這可能是一個內部過濾器該功能,但它是相同的邏輯。

+0

這個deleteModule函數將用完堆棧空間循環依賴。 – Halt