卸载代码/模块

rob*_*rob 49 node.js

我很好奇是否有任何好方法在使用后卸载模块.我有些情况下我需要使用带来大量代码的模块,但很少使用它们(比如作为管理工具),但我不愿意使用它们,因为之后它们可能只会浪费内存,可能会更好用于别处.是否有任何方法可以卸载它们,无论是显式还是允许系统在没有使用一段时间时这样做?

chj*_*hjj 72

是的,可以直接访问模块缓存:

var name = require.resolve('moduleName');
delete require.cache[name];
Run Code Online (Sandbox Code Playgroud)

请注意,如果您的代码带有您想要删除的这些模块所公开的内容的引用,则不会清除它.

(顺便说一句:下边的表面上,require.resolve并且require.cache只是代理来Module._resolveFilenameModule._cache分别与Module作为核心模块加载器,即,require('module')).

  • 这不是一个完整的答案.有些需要加载一个index.js文件,然后加载库的真实内容.例如,尝试require('async')这会加载"... async/lib/async.js",但也会加载"..async/index.js",您可以在require.cache中看到它们.index.js是async.js的父级.因此可能可以取消注册,但可能需要递归函数来删除多个模块. (10认同)
  • 只需执行`for(Object.keys(require.cache)中的var键){delete require.cache [key];}`. (4认同)
  • @Tower,那将卸载所有模块.尝试检查`module.parent`或其他东西可能更好 - 只卸载要卸载的模块.例如,可能不应卸载`util`和`fs`. (4认同)

Chr*_*dam 6

您可以执行以下操作来“卸载”节点模块:

/**
 * 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];
  }
}
Run Code Online (Sandbox Code Playgroud)

“卸载”节点模块意味着您正在从节点需要缓存中“删除”其条目。上面的片段从缓存和所有关联的模块(子模块)中传递删除一个节点模块。

就我而言,我需要“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 下的任何包,等等。这可能是函数内部的过滤器,但它是相同的逻辑。

  • 这个 deleteModule 函数将耗尽循环依赖的堆栈空间。 (2认同)