【问题标题】:How to refresh the requirejs module?如何刷新requirejs模块?
【发布时间】:2015-12-10 17:15:51
【问题描述】:

我有两个模块 settingmap.js

var settingMap = {
    scWidth : [4000, 6000, 8000],
    scHeight : [5000, 7000, 9000],
    bxWidth : [100, 90, 80],
    bxHeight : [100, 90, 80],
    totalTime : [50, 40, 30],
    level : [1, 2, 3],
    boxColor : ['yellow', 'green', 'blue']
};

setting.js

define(['settingmap', 'gamestatus'], function (settingMap, gamestatus) {

    var setting = {
    scWidth : settingMap.scWidth[gamestatus.levelIndex],
    scHeight : settingMap.scHeight[gamestatus.levelIndex],
    bxWidth : settingMap.bxWidth[gamestatus.levelIndex],
    bxHeight : settingMap.bxHeight[gamestatus.levelIndex],
    totalTime : settingMap.totalTime[gamestatus.levelIndex],
    level : settingMap.level[gamestatus.levelIndex],
    maxLevel : settingMap.level.length,
    boxColor : settingMap.boxColor[gamestatus.levelIndex]
    };

    return setting;

});

我在其他模块中使用setting

我会做gamestatus.levelIndex++

但我总是得到没有gamestatus.levelIndex++ 的旧设置。

如何刷新模块setting

【问题讨论】:

    标签: javascript node.js requirejs js-amd


    【解决方案1】:

    这是刷新节点模块(将其从缓存中删除)的方法,以便在下次调用 require 时需要从文件系统中刷新它。

    使用require.resolve 获取require 加载的模块的绝对路径。例如,假设您需要这样的模块:

    var settings = require('./settings.js');
    

    然后你可以像这样从 require 缓存中删除该模块:

    // Use require.resolve to get the full path of the module.
    var modulePath = require.resolve('./settings.js');
    // The full path is the key of the cached module on require.cache.
    delete require.cache[modulePath];
    

    现在您的模块已从缓存中删除。请记住,如果您需要的模块本身也需要其他模块,它们仍将被缓存。这是当我需要我编写的不需要任何其他模块的自定义模块时缓存的样子。

    这是简单地从 npm 请求 bluebird 模块后缓存的样子:

    如您所见,只需要将一堆模块中的 bluebird 加载到缓存中。这在很多情况下都不是问题,但是如果您尝试重置的行为实际上在依赖关系树中更深,那么重新要求 bluebird fresh 可能会重新运行 bluebird 的代码,但是当 bluebird 需要任何那些其他模块,它们将从模块缓存中返回。

    如果您需要清除依赖项及其整个树,请遍历缓存并使用正则表达式。

    Object.keys(require.cache).forEach(function (key) {
      if (key.test(/.*\/projectName\/node\_modules\/moduleName\/.*$/)) {
        delete require.cache[key];
      }
    });
    

    这会在您尝试取消缓存的模块下的项目 node_modules 目录中的任何模块的 require 缓存中查找。在上面的示例中,它将从缓存中删除 bluebird 模块以及缓存在 bluebird 下的任何其他模块。


    注意:我同意 Louis 的观点,您需要这样做表明您可能需要以不同的方式处理事情。

    【讨论】:

    • 只要用于加载模块的唯一东西是Node的require,您的答案就有效,但OP使用的是RequireJS。代码可能在 Node 中运行(这是非常可行的),但如果 OP 想要重新加载加载了 RequireJS 的模块,那么 OP 必须处理 RequireJS 的怪癖,这与 Node 的不同。我已经处理了there(没有区别,只是 RequireJS 的怪癖)。
    • 错过了那一点。我很抱歉。
    【解决方案2】:

    scWidth 定义为getter

    var setting = {
        get scWidth () { 
            return settingMap.scWidth[gamestatus.levelIndex]; 
        }
    };
    

    这样gamestatus.levelIndex 将在您每次想要获取scWidth 的值时进行评估。

    在您当前的代码中,scWidth 被设置为一个值并且不会更改,除非您有其他代码直接分配给它。

    理论上你可以“刷新”一个 RequireJS 模块,但我不提倡使用这种方法来实现你的目标。把它做好是很复杂的。


    您已编辑您的问题以在 settings 中添加一大堆其他值,这些值映射到 settingMap 中的值。很公平,这就是我的做法。在settings 中定义所有遵循settings.<name> -> settingMap.<name>[gamestatus.levelIndex] 模式的字段,然后运行一个循环为所有那些的字段定义getter > 遵循模式:

    // Extend this list to all the fields that follow the pattern.
    var fields = ["scWidth", "scHeight"];
    
    for (var i = 0, field; (field = fields[i]); ++i) {
        (function (field) {
            Object.defineProperty(settings, field, {
                get: function () {
                    return settingMap[field][gamestatus.levelIndex];
                }
            });
        })(field);
    }
    

    这是一段完整的代码,表明它可以工作:

    var gamestatus = {
        levelIndex: 0
    };
    
    var settingMap = {
        "scWidth": [ "scWidth0", "scWidth1"],
        "scHeight": [ "scHeight0", "scHeight1"]
    };
    
    var settings = {
        // Any field that does not follow the pattern can be put here.
        maxLevel : settingMap.level.length
    };
    
    // Extend this list to all the fields that follow the pattern.
    var fields = ["scWidth", "scHeight"];
    
    for (var i = 0, field; (field = fields[i]); ++i) {
        (function (field) {
            Object.defineProperty(settings, field, {
                get: function () {
                    return settingMap[field][gamestatus.levelIndex];
                }
            });
        })(field);
    }
    
    console.log(settings.scWidth);
    console.log(settings.scHeight);
    gamestatus.levelIndex++;
    console.log(settings.scWidth);
    console.log(settings.scHeight);
    

    代码注释:

    1. Getter 以及如何定义它们有据可查 here

    2. 立即调用循环中的匿名函数是为了避免循环中的闭包问题。 (有关问题所在的完整讨论,请参阅 this question。)

    3. 循环的代码:

      for (var i = 0, field; (field = fields[i]); ++i) {
      

      可能是:

      for (var i = 0; i < fields.length; ++i) {
          var field = fields[i];
      

      只要fields 不包含可以评估为false 的值(这里就是这种情况),这两种方法在功能上是等效的。

    【讨论】:

    • 非常感谢。有用!并且非常详细的回答!虽然我还不明白代码XD。我稍后会尝试理解它..以及如何在其中添加maxLevel字段?
    • 查看最新编辑。特别是关于maxLevel:看看我是如何在“完整”的代码中定义它的。 (最长的。)
    猜你喜欢
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多