admin管理员组

文章数量:1321812

I wrote some javascript to run through an array of "modules". For each module it makes an ajax call, gets the html for the module, and dumps the module into one of two columns on the page layout.

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);

        }
    });
}

Problem with this is that the for loop creates a race condition. In the ajax callback module.column is almost always the value of the last module because the for loop finishes long before the ajax callbacks return. How can I maintain the module variable so that each callback is dealing with the appropriate module? Currently all three modules end up in the left column because the last module in the loop is in the left column.

I wrote some javascript to run through an array of "modules". For each module it makes an ajax call, gets the html for the module, and dumps the module into one of two columns on the page layout.

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);

        }
    });
}

Problem with this is that the for loop creates a race condition. In the ajax callback module.column is almost always the value of the last module because the for loop finishes long before the ajax callbacks return. How can I maintain the module variable so that each callback is dealing with the appropriate module? Currently all three modules end up in the left column because the last module in the loop is in the left column.

Share Improve this question edited Jan 31, 2013 at 23:06 ChevCast asked Jan 31, 2013 at 23:04 ChevCastChevCast 59.3k66 gold badges221 silver badges325 bronze badges 1
  • possible duplicate of Javascript closure inside loops - simple practical example – Felix Kling Commented Jan 31, 2013 at 23:38
Add a ment  | 

5 Answers 5

Reset to default 7

You could try creating an extra scope to pass module:

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

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

Edit: If you want you can use forEach as well:

modules.forEach(function(module) {
 // 'module' will be available everywhere in this scope
});

Modify your success callback to this:

$.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));
});

This will create a new scope for the appropriate module variable value.

There's no need to wrap the entire ajax call here.

instead of using the for loop use the jquery's each.. this will solve the problem

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);

        }
    });
}
}
);

That would help

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)
}

Try this way and tell me if it works!

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);

            }
        });
    } ());
}

本文标签: javascriptHow to preserve a variable in an ajax callbackStack Overflow