Как обновить модуль requirejs?

У меня два модуля 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?


person chanjianyi    schedule 14.09.2015    source источник


Ответы (2)


Определите scWidth как геттер:

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

Таким образом, gamestatus.levelIndex будет оцениваться каждый раз, когда вы хотите получить значение scWidth.

В вашем текущем коде scWidth устанавливается в значение один раз и не изменится, если у вас нет другого кода, который присваивает ему непосредственное значение.

Теоретически вы можете «обновить» модуль RequireJS, но я не рекомендую использовать этот подход для достижения поставленной цели. Это сложно сделать правильно.


Вы отредактировали свой вопрос, добавив целую кучу других значений в settings, которые сопоставляются со значениями в settingMap. Достаточно справедливо, вот как я бы это сделал. Определите в settings все поля, которые не соответствуют шаблону settings.<name> -> settingMap.<name>[gamestatus.levelIndex], а затем запустите цикл, чтобы определить геттеры для всех тех полей, которые соответствуют шаблону:

// 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. Геттеры и то, как их определить, хорошо задокументированы здесь.

  2. Анонимная функция в цикле, которая вызывается сразу, предназначена для того, чтобы избежать проблемы замыкания в циклах. (См. этот вопрос для полного обсуждения проблемы. )

  3. Код цикла:

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

    может быть:

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

    Два способа сделать это функционально эквивалентны до тех пор, пока fields не содержит значение, которое может быть оценено как false (что имеет место здесь).

person Louis    schedule 14.09.2015
comment
Большое тебе спасибо. оно работает! и очень подробный ответ! Хотя я еще не понимаю код XD. Позже попробую разобраться.. а как добавить в него поле maxLevel? - person chanjianyi; 14.09.2015
comment
Смотрите последние изменения. В частности, что касается maxLevel: посмотрите, как я определил его в полном фрагменте кода. (Самый длинный.) - person Louis; 14.09.2015

Вот как вы обновляете модуль узла (удаляете его из кеша), чтобы он требовался свежим из файловой системы при следующем вызове require.

Используйте require.resolve, чтобы получить абсолютный путь к модулю, загруженному require. Например, допустим, вам нужен ваш модуль следующим образом:

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

Затем вы можете удалить этот модуль из требуемого кеша следующим образом:

// 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];

Теперь ваш модуль удален из кеша. Имейте в виду, что если для требуемого модуля также требуются другие модули, они все равно будут кэшироваться. Вот как выглядит кеш, когда мне требуется написанный мной пользовательский модуль, который не требует никаких других модулей.

Вот как выглядит кеш после простого запроса модуля bluebird из npm:

Как видите, просто требуется, чтобы 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 вашего проекта под модулем, который вы пытаетесь раскешировать. В приведенном выше примере он удалит модуль bluebird из кеша, а также любые другие модули, кэшированные под bluebird.


ПРИМЕЧАНИЕ. Я согласен с Луисом в том, что тот факт, что вам нужно сделать это, является признаком того, что вам, вероятно, нужно действовать по-другому.

person Chev    schedule 14.09.2015
comment
Ваш ответ работает до тех пор, пока для загрузки модулей используется только Node require, но OP использует RequireJS. Код может работать в Node (что вполне выполнимо), но если OP хочет перезагрузить модуль, загруженный с помощью RequireJS, OP должен иметь дело с причудами RequireJS, которые отличаются от Node. Я имел дело с этим здесь (не разница, а просто особенности RequireJS). - person Louis; 14.09.2015
comment
Пропустил этот бит. Мои извинения. - person Chev; 14.09.2015