Повторяющийся код "Outsource" в функцию с параметрами (js)

Поэтому я использую один файл js для загрузки нескольких файлов html и js всякий раз, когда они необходимы. У меня есть рабочий код для множества модулей. В приведенном ниже примере вы можете увидеть первые два модуля. Все они выглядят одинаково. Теперь я хочу "перевести" повторяющийся код в функцию с параметрами, чтобы общий объем кода был минимизирован. Так как я никогда не делал что-то подобное раньше, мне могла бы понадобиться некоторая помощь (сейчас я изучаю js). Я был бы очень признателен за помощь.

 //first module
 if (moduleID === "placeone") {
            var isLoaded = 0;
            if (isLoaded) {
                console.log("file already loaded");
                returnValue = new PlaceOneModule(id, moduleInitialData);
            }
            $("#placeone").load("html/modules/PlaceOneModule.html", function (response, status, xhr) {
                console.log("PlaceOneModule.html" + " " + status);
                $.getScript("js/modules/PlaceOneModule.js").done(function () {
                    console.log("PlaceOneModule.js geladen");
                    isLoaded = 1;
                    returnValue = new PlaceOneModule(id, moduleInitialData);
                }).fail(function () {
                    console.log("PlaceOneModule.js nicht geladen");
                });
            });
        }

    //second module
        if (moduleID === "placetwo") {
            var isLoaded = 0;
            if (isLoaded) {
                console.log("file already loaded");
                returnValue = new PlaceTwoModule(id, moduleInitialData);
            }
            $("#placetwo").load("html/modules/PlaceTwoModule.html", function (response, status, xhr) {
                console.log("PlaceTwoModule.html" + " " + status);
                $.getScript("js/modules/PlaceTwoModule.js").done(function () {
                    console.log("PlaceTwoModule.js geladen");
                    isLoaded = 1;
                    returnValue = new PlaceTwoModule(id, moduleInitialData);
                }).fail(function () {
                    console.log("PlaceTwoModule.js nicht geladen");
                });
            });
        }

2 ответа

Решение

На вопрос довольно сложно ответить, так как есть много вещей, которые нужно учитывать.

var cache = {};

function module(name, target, done) {
    if (!(name in cache)) {
        return $(target).load('html/modules/' + name + '.html', function(response, status, xhr) {
            console.log(name + '.html ' + status);

            $.getScript('js/modules/' + name + '.js')
                .done(function() {
                    console.log(name + '.js geladen');
                    cache[name] = window[name];

                    done(null, cache[name]);
                })
                .fail(function() {
                    var message = name + '.js nicht geladen';

                    cache[name] = function() {
                        console.error(message);
                    };

                    done(message);
                });
        });
    }

    setTimeout(function() {
        done(null, cache[name]);
    }, 0);
}

Я постараюсь объяснить мой ход мыслей за этим:

  • var cache = {} - вам нужно что-то, чтобы отслеживать каждый отдельный модуль
  • function module(name, target, done) {
    • name будет базовым именем вашего модуля, например PlaceTwoModuleэто уже использовалось последовательно в файлах html и js и имени функции js
    • target будет селектором, в который должен быть загружен HTML-файл
    • поскольку одно из действий, которые вы выполняете, требует асинхронной операции, все функции должны стать асинхронными, я ввожу обратный вызов (done) аргумент
  • if (!(name in cache)) - если модуль еще не кэширован, он требует выборки, поэтому load срабатывает первым делом
  • однажды load завершает, он уволит $.getScript
    • если $.getScript работает, name будет считаться в window и ссылка хранится в cache переменная, после этого done обратный вызов вызывается (с функцией в качестве второго аргумента).
    • если $.getScript не получилось, мы добавили функцию к cacheкоторый ничего не делает, кроме как сказать вам, что это не сработает, после этого done обратный вызов вызывается (с ошибкой в ​​качестве первого аргумента).
  • если name существовал в cacheмы будем называть done обратный вызов сразу после выхода из module функция

Итак, как это использовать? Теперь все сводится к module функция

module('#placeone', 'PlaceOneModule', function(error, PlaceModule) {
  if (error) throw new Error(error);

  var instance = new PlaceModule(id, initial);

  // ...
}

Я использовал общий function(error, value) {..} подпись для функции обратного вызова, которая всегда имеет ошибку в качестве первого аргумента (что позволяет добавлять и аргументировать другие аргументы).

Есть некоторые предостережения / предположения, которые стоит упомянуть:

  • Я не предоставил отказоустойчивый для предотвращения нескольких загрузок одного и того же модуля (так же, как в вашем примере), если ранее звонки module все еще загружаются
  • не важно что target Вы вызываете module с, он загрузится только один раз (ну, смотрите предыдущую строку;-))
  • Я предполагаю, что загруженные модули находятся в глобальном (window) для того, чтобы пример был простым, имейте в виду, что "не загрязняйте глобальный охват"

Это стало довольно сложным ответом, я надеюсь, что объяснил каждый шаг достаточно.

Что-то вроде этого возможно:

 var modules = [];
 modules.push({
   js: 'PlaceOneModule',
   id: 'placeone'
 });

 modules.push({
   js: 'PlaceTwoModule',
   id: 'placetwo'
 });

 var module = modules.filter(function(m) {
   return m.id === moduleID;
 });

 if (module) {
   var isLoaded = 0;
   if (!!window[module.js]) {
      console.log("file already loaded");
      returnValue = window[module.js];
   }

   $("#" + module.id).load("html/modules/" + module.js + ".html", function(response, status, xhr) {
     $.getScript("js/modules/" + module.js + ".js").done(function() {
        returnValue = new window[module.js](id, moduleInitialData);
     }).fail(function() {
        console.log("PlaceOneModule.js nicht geladen");
     });
   });
 }
Другие вопросы по тегам