node.js require() 缓存 - 可能失效?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9210542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
node.js require() cache - possible to invalidate?
提问by William
From the node.js documentation:
从 node.js 文档:
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
模块在第一次加载后被缓存。这意味着(除其他外)每次调用 require('foo') 都会返回完全相同的对象,如果它解析为相同的文件。
Is there a way to invalidate this cache? i.e. for unit testing, I'd like each test to be working on a fresh object.
有没有办法使这个缓存无效?即对于单元测试,我希望每个测试都在一个新对象上工作。
采纳答案by kaisa1028
You can always safely delete an entry in require.cache without a problem, even when there are circular dependencies. Because when you delete, you just delete a reference to the cached module object, not the module object itself, the module object will not be GCed because in case of circular dependencies, there is still a object referencing this module object.
您始终可以安全地删除 require.cache 中的条目而不会出现问题,即使存在循环依赖项也是如此。因为当你删除时,你只是删除对缓存模块对象的引用,而不是模块对象本身,模块对象不会被 GCed,因为在循环依赖的情况下,仍然有一个对象引用这个模块对象。
Suppose you have:
假设你有:
script a.js:
脚本 a.js:
var b=require('./b.js').b;
exports.a='a from a.js';
exports.b=b;
and script b.js:
和脚本 b.js:
var a=require('./a.js').a;
exports.b='b from b.js';
exports.a=a;
when you do:
当你这样做时:
var a=require('./a.js')
var b=require('./b.js')
you will get:
你会得到:
> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js', a: undefined }
now if you edit your b.js:
现在,如果你编辑你的 b.js:
var a=require('./a.js').a;
exports.b='b from b.js. changed value';
exports.a=a;
and do:
并做:
delete require.cache[require.resolve('./b.js')]
b=require('./b.js')
you will get:
你会得到:
> a
{ a: 'a from a.js', b: 'b from b.js' }
> b
{ b: 'b from b.js. changed value',
a: 'a from a.js' }
===
===
The above is valid if directly running node.js. However, if using tools that have their own module caching system, such as jest, the correct statement would be:
如果直接运行node.js,以上是有效的。但是,如果使用具有自己的模块缓存系统的工具,例如jest,则正确的语句将是:
jest.resetModules();
回答by luff
If you always want to reload your module, you could add this function:
如果你总是想重新加载你的模块,你可以添加这个函数:
function requireUncached(module) {
delete require.cache[require.resolve(module)];
return require(module);
}
and then use requireUncached('./myModule')instead of require.
然后使用requireUncached('./myModule')而不是要求。
回答by Ben Barkay
Yes, you can access the cache via require.cache[moduleName]where moduleNameis the name of the module you wish to access. Deleting an entry by calling delete require.cache[moduleName]will cause requireto load the actual file.
是的,你可以通过访问高速缓存require.cache[moduleName]这里moduleName是您要访问的模块的名称。通过调用删除条目delete require.cache[moduleName]将导致require加载实际文件。
This is how you would remove all cached files associated with the module:
这是删除与模块关联的所有缓存文件的方法:
/**
* 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));
}
};
Usage would be:
用法是:
// Load the package
var mypackage = require('./mypackage');
// Purge the package from cache
purgeCache('./mypackage');
Since this code uses the same resolver requiredoes, just specify whatever you would for require.
由于此代码使用相同的解析器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
“Unix 的设计目的不是阻止用户做愚蠢的事情,因为这也会阻止他们做聪明的事情。” — 道格·格温
I think that there shouldhave been a way for performing an explicit uncached module loading.
我认为应该有一种方法可以执行显式的未缓存模块加载。
回答by nelsonic
There's a Simple Module for that(with tests)
有一个简单的模块(带有测试)
We had this exact issue while testingour code (delete cached modules so they can be re-required in a fresh state) so we reviewed all the suggestionsof people on the various StackOverflow Questions & Answers and put together a simplenode.js module(with tests):
我们在测试我们的代码时遇到了这个确切的问题(删除缓存的模块,以便它们可以在新的状态下重新需要),所以我们查看了人们在各种 StackOverflow 问答中的所有建议,并组合了一个简单的node.js 模块(带测试):
As you would expect, works for bothpublished npm packages and locallydefined modules. Windows, Mac, Linux, etc.
正如你所期望的,适用于这两种出版NPM包和本地定义的模块。Windows、Mac、Linux 等。
How? (usage)
如何?(用法)
Usage is pretty simple:
用法非常简单:
install
安装
Install the module from npm:
从 npm 安装模块:
npm install decache --save-dev
npm install decache --save-dev
Use it in your code:
在您的代码中使用它:
// 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)
If you have any questions or need more examples, please create a GitHub issue: https://github.com/dwyl/decache/issues
如果您有任何问题或需要更多示例,请创建一个 GitHub 问题:https: //github.com/dwyl/decache/issues
回答by Tim Malone
For anyone coming across this who is using Jest, because Jest does its own module caching, there's a built-in function for this - just make sure jest.resetModulesruns eg. after each of your tests:
对于任何使用 Jest 的人来说,因为 Jest 有自己的模块缓存,所以有一个内置函数 - 只需确保jest.resetModules运行,例如。每次测试后:
afterEach( function() {
jest.resetModules();
});
Found this after trying to use decachelike another answer suggested. Thanks to Anthony Garvan.
在尝试像另一个建议的答案一样使用decache后发现了这一点。感谢安东尼加文。
Function documentation here.
功能文档在这里。
回答by fedorqui 'SO stop harming'
The solutions is to use:
解决方法是使用:
delete require.cache[require.resolve(<path of your script>)]
Find here some basic explanations for those who, like me, are a bit new in this:
在这里为那些像我一样对此有点陌生的人找到一些基本解释:
Suppose you have a dummy example.jsfile in the root of your directory:
假设您example.js的目录根目录中有一个虚拟文件:
exports.message = "hi";
exports.say = function () {
console.log(message);
}
Then you require()like this:
那你require()喜欢这个:
$ node
> require('./example.js')
{ message: 'hi', say: [Function] }
If you then add a line like this to example.js:
如果然后添加这样的行到example.js:
exports.message = "hi";
exports.say = function () {
console.log(message);
}
exports.farewell = "bye!"; // this line is added later on
And continue in the console, the module is not updated:
并在控制台中继续,模块未更新:
> require('./example.js')
{ message: 'hi', say: [Function] }
That's when you can use delete require.cache[require.resolve()]indicated in luff's answer:
那时你可以使用luff 的回答中delete require.cache[require.resolve()]指出的:
> delete require.cache[require.resolve('./example.js')]
true
> require('./example.js')
{ message: 'hi', say: [Function], farewell: 'bye!' }
So the cache is cleaned and the require()captures the content of the file again, loading all the current values.
因此缓存被清除并require()再次捕获文件的内容,加载所有当前值。
回答by daniellmb
rewireis great for this use case, you get a new instance with each call. Easy dependency injection for node.js unit testing.
rewire非常适合这个用例,每次调用都会得到一个新实例。node.js 单元测试的简单依赖注入。
rewire adds a special setter and getter to modules so you can modify their behaviour for better unit testing. You may
rewire 为模块添加了一个特殊的 setter 和 getter,因此您可以修改它们的行为以进行更好的单元测试。你可以
inject mocks for other modules or globals like process leak private variables override variables within the module. rewire does not load the file and eval the contents to emulate node's require mechanism. In fact it uses node's own require to load the module. Thus your module behaves exactly the same in your test environment as under regular circumstances (except your modifications).
为其他模块或全局变量注入模拟,例如进程泄漏私有变量覆盖模块内的变量。rewire 不会加载文件并评估内容以模拟节点的 require 机制。实际上它使用节点自己的 require 来加载模块。因此,您的模块在您的测试环境中的行为与在常规情况下完全相同(除了您的修改)。
Good news to all caffeine-addicts: rewire works also with Coffee-Script. Note that in this case CoffeeScript needs to be listed in your devDependencies.
所有咖啡因成瘾者的好消息:rewire 也适用于 Coffee-Script。请注意,在这种情况下,需要在您的 devDependencies 中列出 CoffeeScript。
回答by Krzysztof Wende
I'd add to luff's answer one more line and change the parameter name:
我会在 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)
}
回答by Henry Tseng
Yes, you can invalidate cache.
是的,您可以使缓存无效。
The cache is stored in an object called require.cache which you can access directly according to filenames (e.g. - /projects/app/home/index.jsas opposed to ./homewhich you would use in a require('./home')statement).
缓存存储在一个名为 require.cache 的对象中,您可以根据文件名直接访问它(例如 -/projects/app/home/index.js与./home您在require('./home')语句中使用的相反)。
delete require.cache['/projects/app/home/index.js'];
Our team has found the following module useful. To invalidate certain groups of modules.
我们的团队发现以下模块很有用。使某些模块组无效。
回答by atomh33ls
I am not 100% certain of what you mean by 'invalidate', but you can add the following above the requirestatements to clear the cache:
我不是 100% 确定您所说的“无效”是什么意思,但您可以在require语句上方添加以下内容以清除缓存:
Object.keys(require.cache).forEach(function(key) { delete require.cache[key] })
Taken from @Dancrumb's comment here
从@ Dancrumb的评论采取这里


