在node.js文档中:

模块在第一次加载后被缓存。这意味着(除其他外)每次调用require('foo')都会得到完全相同的返回对象,如果它将解析到相同的文件。

是否有一种方法使这个缓存无效?例如,对于单元测试,我希望每个测试都在一个新鲜的对象上工作。


当前回答

下面是我对这个问题的回答,它处理如果文件有(例如)语法错误就不加载的问题

function reacquire(module) {
const fullpath  = require.resolve(module);
const backup = require.cache[fullpath];
delete require.cache[fullpath];

 try {
   const newcopy = require(module);
   console.log("reqcquired:",module,typeof newcopy);
   return newcopy;
 } catch (e) {
    console.log("Can't reqcquire",module,":",e.message);
    require.cache[fullpath] = backup;
    return backup;
 }

}

其他回答

有一个简单模块(带测试)

我们在测试代码时遇到了这个问题(删除缓存模块,以便它们可以在新鲜状态下重新使用),所以我们审查了人们在各种StackOverflow问答上的所有建议,并将一个简单的node.js模块(带测试)放在一起:

https://www.npmjs.com/package/decache

如你所料,它既适用于已发布的npm包,也适用于本地定义的模块。Windows, Mac, Linux等等。

怎么做?(使用)

用法非常简单:

安装

从npm安装模块:

NPM安装decache——save-dev

在你的代码中使用它:

// require the decache module:
const decache = require('decache');

// require a module that you wrote"
let mymod = require('./mymodule.js');

// use your module the way you need to:
console.log(mymod.count()); // 0   (the initial state for our counter is zero)
console.log(mymod.incrementRunCount()); // 1

// delete the cached module:
decache('./mymodule.js');

//
mymod = require('./mymodule.js'); // fresh start
console.log(mymod.count()); // 0   (back to initial state ... zero)

如果你有任何问题或需要更多的例子,请创建一个GitHub问题: https://github.com/dwyl/decache/issues

您总是可以安全地删除require中的条目。缓存没有问题,即使有循环依赖。因为当你删除时,你只是删除了缓存的模块对象的引用,而不是模块对象本身,模块对象不会被GCed,因为在循环依赖的情况下,仍然有一个对象引用这个模块对象。

假设你有:

脚本a.js:

var b=require('./b.js').b;
exports.a='a from a.js';
exports.b=b;

和脚本b.js:

var a=require('./a.js').a;
exports.b='b from b.js';
exports.a=a;

当你这样做时:

var a=require('./a.js')
var b=require('./b.js')

你会得到:

> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js', a: undefined }

现在如果你编辑你的b.js:

var a=require('./a.js').a;
exports.b='b from b.js. changed value';
exports.a=a;

和做的事:

delete require.cache[require.resolve('./b.js')]
b=require('./b.js')

你会得到:

> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js. changed value',
  a: 'a from a.js' }

===

如果直接运行node.js,上述语句有效。然而,如果使用的工具有自己的模块缓存系统,比如jest,正确的语句应该是:

jest.resetModules();

如果是用于单元测试,另一个可以使用的好工具是proxyquire。每次你代理模块时,它都会使模块缓存失效,并缓存一个新的模块。它还允许您修改正在测试的文件所需的模块。

是的,您可以通过require访问缓存。缓存[moduleName],其中moduleName是你想要访问的模块名。通过调用delete require删除一个条目。cache[moduleName]将导致require加载实际文件。

这是删除与模块相关的所有缓存文件的方法:

/**
 * Removes a module from the cache
 */
function purgeCache(moduleName) {
    // Traverse the cache looking for the files
    // loaded by the specified module name
    searchCache(moduleName, function (mod) {
        delete require.cache[mod.id];
    });

    // Remove cached paths to the module.
    // Thanks to @bentael for pointing this out.
    Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
        if (cacheKey.indexOf(moduleName)>0) {
            delete module.constructor._pathCache[cacheKey];
        }
    });
};

/**
 * Traverses the cache to search for all the cached
 * files of the specified module name
 */
function searchCache(moduleName, callback) {
    // Resolve the module identified by the specified name
    var mod = require.resolve(moduleName);

    // Check if the module has been resolved and found within
    // the cache
    if (mod && ((mod = require.cache[mod]) !== undefined)) {
        // Recursively go over the results
        (function traverse(mod) {
            // Go over each of the module's children and
            // traverse them
            mod.children.forEach(function (child) {
                traverse(child);
            });

            // Call the specified callback providing the
            // found cached module
            callback(mod);
        }(mod));
    }
};

用法如下:

// Load the package
var mypackage = require('./mypackage');

// Purge the package from cache
purgeCache('./mypackage');

因为这段代码使用了相同的解析器require does,所以只需要为require指定所需的内容。


Unix的设计初衷并不是为了阻止用户做愚蠢的事情 这也会阻止他们做一些聪明的事情。”——道格·格温

我认为应该有一种方法来执行显式的非缓存模块加载。

我不是100%确定你说的“invalidate”是什么意思,但你可以在require语句上面添加以下语句来清除缓存:

Object.keys(require.cache).forEach(function(key) { delete require.cache[key] })

摘自@Dancrumb的评论