Я написал Javascript для запуска через массив «модулей». Для каждого модуля он вызывает ajax, получает html для модуля и выдает модуль в один из двух столбцов макета страницы.

var modules = [
    { name: 'ExchangeStatus', title: 'Exchange Status', column: 'left' },
    { name: 'Grid', title: 'Contacts', column: 'right' }
    { name: 'Filters', title: 'Filters', column: 'left' }
],
modulesUrl = '/Modules/';

for (var count = 0; count < modules.length; count++) {
    var module = modules[count];

    // Get module HTML.
    $.ajax({
        url: modulesUrl + module.name,
        success: function (moduleHtml) {

            // Append module HTML to appropriate element.
            $('#' + module.column + 'Column').append(moduleHtml);

            // Custom event to trigger the module to load its data.
            var initializeModuleEvent = $.Event('initialize' + module.name);
            initializeModuleEvent.firstLoad = true;
            $(document).trigger(initializeModuleEvent);

        }
    });
}

Проблема в том, что цикл for создает состояние гонки. В обратном вызове ajax module.column почти всегда значение последнего модуля, потому что цикл for завершается задолго до возврата обратных вызовов ajax. Как мне сохранить переменную модуля, чтобы каждый обратный вызов имел дело с соответствующим модулем? В настоящее время все три модуля оказываются в левом столбце, поскольку последний модуль в цикле находится в левом столбце.

2
Chev 1 Фев 2013 в 03:04

5 ответов

Лучший ответ

Вы можете попробовать создать дополнительную область для передачи module:

for (var count = 0; count < modules.length; count++) {
    var module = modules[count];

    (function(module) {
      $.ajax({
        ...
      })
    }(module));

Изменить . Если хотите, вы также можете использовать forEach:

modules.forEach(function(module) {
 // 'module' will be available everywhere in this scope
});
7
elclanrs 31 Янв 2013 в 23:42

Измените ваш успешный обратный вызов на это:

$.ajax({
    url: modulesUrl + module.name,
    success: (function (module) {
        return function (moduleHtml) {
            // Append module HTML to appropriate element.
            $('#' + module.column + 'Column').append(moduleHtml);

            // Custom event to trigger the module to load its data.
            var initializeModuleEvent = $.Event('initialize' + module.name);
            initializeModuleEvent.firstLoad = true;
            $(document).trigger(initializeModuleEvent);
        };
    }(module));
});

Это создаст новую область видимости для соответствующего значения переменной module.

Нет необходимости оборачивать весь вызов ajax здесь.

2
Brian Ustas 31 Янв 2013 в 23:09

Вместо использования цикла for используйте jquery для каждого .. это решит проблему

var modules = [
    { name: 'ExchangeStatus', title: 'Exchange Status', column: 'left' },
    { name: 'Grid', title: 'Contacts', column: 'right' }
    { name: 'Filters', title: 'Filters', column: 'left' }
],
modulesUrl = '/Modules/';

$(modules).each( function(index, elem)
{
    var module = elem;

    // Get module HTML.
    $.ajax({
        url: modulesUrl + module.name,
        success: function (moduleHtml) {

            // Append module HTML to appropriate element.
            $('#' + module.column + 'Column').append(moduleHtml);

            // Custom event to trigger the module to load its data.
            var initializeModuleEvent = $.Event('initialize' + module.name);
            initializeModuleEvent.firstLoad = true;
            $(document).trigger(initializeModuleEvent);

        }
    });
}
}
);
2
pranag 31 Янв 2013 в 23:29

Это помогло бы

for (var count = 0; count < modules.length; count++) {
    var module = modules[count];

    (function (module) {
        // Get module HTML.
        $.ajax({
            url: modulesUrl + module.name,
            success: function (moduleHtml) {

                // Append module HTML to appropriate element.
                $('#' + module.column + 'Column').append(moduleHtml);

                // Custom event to trigger the module to load its data.
                var initia`enter code here`lizeModuleEvent = $.Event('initialize' + module.name);
                initializeModuleEvent.firstLoad = true;
                $(document).trigger(initializeModuleEvent);

            }
        });
    })(module)
}
1
kidwon 31 Янв 2013 в 23:08

Попробуйте таким образом и скажите мне, если это работает!

for (var n = 0; n < modules.length; n++) {
(function () {
    var i = n;
        var module = modules[i];

        // Get module HTML.
        $.ajax({
            url: modulesUrl + module.name,
            success: function (moduleHtml) {

                // Append module HTML to appropriate element.
                $('#' + module.column + 'Column').append(moduleHtml);

                // Custom event to trigger the module to load its data.
                var initializeModuleEvent = $.Event('initialize' + module.name);
                initializeModuleEvent.firstLoad = true;
                $(document).trigger(initializeModuleEvent);

            }
        });
    } ());
}
0
Juan Pablo Rossi Querin 31 Янв 2013 в 23:17