最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to preserve a variable in an ajax callback? - Stack Overflow

programmeradmin5浏览0评论

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

            }
        });
    } ());
}
发布评论

评论列表(0)

  1. 暂无评论