Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
node.js require()缓存-可能会失效吗?_Node.js - Fatal编程技术网

node.js require()缓存-可能会失效吗?

node.js require()缓存-可能会失效吗?,node.js,Node.js,从node.js文档中: 模块在第一次加载后被缓存。这意味着(除其他外)每个对require('foo')的调用都将返回完全相同的对象,前提是它将解析为相同的文件 有没有办法使这个缓存失效?i、 e.对于单元测试,我希望每个测试都在一个新对象上进行。即使存在循环依赖项,您始终可以安全地删除require.cache中的条目,而不会出现问题。因为当您删除时,您只是删除对缓存模块对象的引用,而不是模块对象本身,模块对象将不会被GCD,因为在循环依赖的情况下,仍然有一个对象引用此模块对象 假设你有:

从node.js文档中:

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


有没有办法使这个缓存失效?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;
 }

}