node.js require()缓存-可能会失效吗?
从node.js文档中: 模块在第一次加载后被缓存。这意味着(除其他外)每个对require('foo')的调用都将返回完全相同的对象,前提是它将解析为相同的文件node.js require()缓存-可能会失效吗?,node.js,Node.js,从node.js文档中: 模块在第一次加载后被缓存。这意味着(除其他外)每个对require('foo')的调用都将返回完全相同的对象,前提是它将解析为相同的文件 有没有办法使这个缓存失效?i、 e.对于单元测试,我希望每个测试都在一个新对象上进行。即使存在循环依赖项,您始终可以安全地删除require.cache中的条目,而不会出现问题。因为当您删除时,您只是删除对缓存模块对象的引用,而不是模块对象本身,模块对象将不会被GCD,因为在循环依赖的情况下,仍然有一个对象引用此模块对象 假设你有:
有没有办法使这个缓存失效?i、 e.对于单元测试,我希望每个测试都在一个新对象上进行。即使存在循环依赖项,您始终可以安全地删除require.cache中的条目,而不会出现问题。因为当您删除时,您只是删除对缓存模块对象的引用,而不是模块对象本身,模块对象将不会被GCD,因为在循环依赖的情况下,仍然有一个对象引用此模块对象 假设你有: 脚本a.js: 和脚本b.js: 当您这样做时:
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 }
> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js. changed value',
a: 'a from a.js' }
现在,如果您编辑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', a: undefined }
> 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();
// Load the package
var mypackage = require('./mypackage');
// Purge the package from cache
purgeCache('./mypackage');
是的,您可以通过
require.cache[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));
}
};
用途如下:
jest.resetModules();
// Load the package
var mypackage = require('./mypackage');
// Purge the package from cache
purgeCache('./mypackage');
因为这段代码使用了与require相同的解析器,所以只需指定所需的内容即可
“Unix的设计并不是为了阻止用户做愚蠢的事情,就像 这也会阻止他们做聪明的事情
我认为应该有一种方法来执行显式的未缓存模块加载。如果您总是想重新加载模块,可以添加以下功能:
function requireUncached(module) {
delete require.cache[require.resolve(module)];
return require(module);
}
然后使用
requireUncached('./myModule')
而不是require。我会在luff的答案中再添加一行并更改参数名称:
function requireCached(_module){
var l = module.children.length;
for (var i = 0; i < l; i++)
{
if (module.children[i].id === require.resolve(_module))
{
module.children.splice(i, 1);
break;
}
}
delete require.cache[require.resolve(_module)];
return require(_module)
}
所需功能已存档(\u模块){
var l=module.childrence.length;
对于(变量i=0;i
非常适合此用例,每次调用都会得到一个新实例。轻松地为node.js单元测试注入依赖项
rewire为模块添加了一个特殊的setter和getter,这样您就可以修改它们的行为,以更好地进行单元测试。你可以
为其他模块或全局类进程注入模拟
泄漏私有变量
重写模块内的变量。
重新布线不会加载文件并评估内容以模拟节点的require机制。事实上,它使用节点自己的需求来加载模块。因此,您的模块在测试环境中的行为与在常规情况下完全相同(除了您的修改)
对所有咖啡因上瘾者来说,这是个好消息:rewire也适用于咖啡脚本。请注意,在这种情况下,CoffeeScript需要列在您的devDependencies中。我无法在答案的注释中巧妙地添加代码。但我会使用@Ben Barkay的答案,然后将其添加到
require.uncache
函数中
// see https://github.com/joyent/node/issues/8266
// use in it in @Ben Barkay's require.uncache function or along with it. whatever
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if ( cacheKey.indexOf(moduleName) > -1 ) {
delete module.constructor._pathCache[ cacheKey ];
}
});
假设您需要一个模块,然后卸载它,然后重新安装同一个模块,但使用了不同的版本,其包中有不同的主脚本。json,下一个要求将失败,因为主脚本不存在,因为它缓存在模块中。_pathCache
有一个简单的模块(带有测试)
我们在测试代码时遇到了这个问题(删除缓存模块,以便在新状态下重新需要它们),因此我们审查了人们对各种StackOverflow问题和答案的所有建议,并将一个简单的node.js模块整合在一起(带有测试):
正如您所期望的,它适用于已发布的npm包和本地定义的模块。Windows、Mac、Linux等
怎么用?(用法)
用法非常简单:
安装
从npm安装模块:
npm安装decache--保存开发文件
在代码中使用它:
如果您有任何问题或需要更多示例,请创建GitHub问题:
以下两步操作对我来说非常有效。 动态更改
模型
文件i-e'mymodule.js'
后,需要先删除中的预编译模型,然后使用
是的,您可以使缓存无效 缓存存储在名为require.cache的对象中,您可以根据文件名直接访问该对象(例如-
/projects/app/home/index.js
,而不是/home
,您可以在require('./home')
语句中使用该对象)
我们的团队发现以下模块很有用。使某些模块组无效
解决方案是使用:
delete require.cache[require.resolve(<path of your script>)]
然后您可以像这样require()
:
$ node
> require('./example.js')
{ message: 'hi', say: [Function] }
如果您随后在example.js
中添加类似的行:
exports.message = "hi";
exports.say = function () {
console.log(message);
}
exports.farewell = "bye!"; // this line is added later on
并在控制台中继续,模块未更新:
> require('./example.js')
{ message: 'hi', say: [Function] }
此时,您可以使用delete require.cache[require.resolve()]
如所示:
因此,缓存被清理,并且
require()
再次捕获文件内容,加载所有当前值。如果是用于单元测试,另一个好工具是。每次您请求模块时,它都会使模块缓存无效并缓存一个新的模块缓存。它还允许您修改正在测试的文件所需的模块。对于使用Jest的任何人来说,因为Jest有自己的模块缓存,所以它有一个内置的功能-只需制作
exports.message = "hi";
exports.say = function () {
console.log(message);
}
exports.farewell = "bye!"; // this line is added later on
> require('./example.js')
{ message: 'hi', say: [Function] }
> delete require.cache[require.resolve('./example.js')]
true
> require('./example.js')
{ message: 'hi', say: [Function], farewell: 'bye!' }
afterEach( function() {
jest.resetModules();
});
// random.js
module.exports = Math.random()
const forget = require('require-and-forget')
const r1 = forget('./random')
const r2 = forget('./random')
// r1 and r2 will be different
// "random.js" will not be stored in the require.cache
Object.keys(require.cache).forEach(function(key) { delete require.cache[key] })
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;
}
}