问:
下面这段来自于node.js文档:
模块在第一次载入后就被缓存起来了。这意味着(在其它地方)每一次调用require('foo')将会返回同样的一个对象,如果它被解析为同一个文件。
有没有方法让这个缓存失效?这是为了单元测试,我想要让每一个测试检测的是全新的对象。
答1:
你总可以安全删去require.cache中的某个入口,这没有任何问题,即使里面存在着循环依赖。因为当你删除的时候,你只是删除了这项该缓存模块对象的引用,而不是模块对象本身,该模块对象将不会被垃圾回收以防循环引用,仍然会有一个对象引用指向该模块对象。假设你有一个脚本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' }
答2:
当然可以,你可以通过require.cache[moduleName]的方式来操作cache,前提是moduleName是你想要访问的模块的名字。通过delete require.cache[moduleName]命令来删除某个入口,将会导致require重新去加载真正的文件。
下面是一段代码,能移除所有跟该模块相关的文件的缓存:
/**
* 从缓存中移除module
*/
function purgeCache(moduleName) {
// 遍历缓存来找到通过指定模块名载入的文件
searchCache(moduleName, function (mod) {
delete require.cache[mod.id];
});
// 删除模块缓存的路径
// 多谢@bentael指出这点
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if (cacheKey.indexOf(moduleName)>0) {
delete module.constructor._pathCache[cacheKey];
}
});
};
/**
* 遍历缓存来查找通过特定模块名缓存下的模块
*/
function searchCache(moduleName, callback) {
// 通过指定的名字resolve模块
var mod = require.resolve(moduleName);
// 检查该模块在缓存中是否被resolved并且被发现
if (mod && ((mod = require.cache[mod]) !== undefined)) {
// 递归的检查结果
(function traverse(mod) {
// 检查该模块的子模块并遍历它们
mod.children.forEach(function (child) {
traverse(child);
});
// 调用指定的callback方法,并将缓存的module当做参数传入
callback(mod);
}(mod));
}
};
使用方法如下:
// 载入包
var mypackage = require('./mypackage');
// 从cache中清除该包
purgeCache('./mypackage');
因为这段代码使用了和require同样的resolver,所以你可以指定任意你想要require的模块。
"Unix was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things." – Doug Gwyn
我认为应该有一种方法来显式的加载非缓存模块。
网友评论