2011-07-13 30 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