美文网首页我爱编程
[译] node.js require()的缓存-可以使其失效吗

[译] node.js require()的缓存-可以使其失效吗

作者: d6e83ee69161 | 来源:发表于2017-04-11 01:39 被阅读2522次

    原文:node.js require() cache - possible to invalidate?

    问:

    下面这段来自于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

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

    相关文章

      网友评论

        本文标题:[译] node.js require()的缓存-可以使其失效吗

        本文链接:https://www.haomeiwen.com/subject/uhxyattx.html