【问题标题】:How to preserve a variable in an ajax callback?如何在ajax回调中保留变量?
【发布时间】:2013-01-16 04:52:45
【问题描述】:

我编写了一些 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 回调返回之前很久就完成了。如何维护模块变量,以便每个回调处理适当的模块?目前所有三个模块都在左列中,因为循环中的最后一个模块在左列中。

【问题讨论】:

标签: javascript jquery ajax asp.net-mvc asynchronous


【解决方案1】:

您可以尝试创建一个额外的范围来传递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
});

【讨论】:

  • 非常感谢!我觉得自己没有考虑使用闭包很愚蠢,但我真的很感激:D
  • 这不是唯一的选择,但也是最明显的。你可以使用forEach,如果你想忘记闭包。
  • 我没有意识到 javascript 有一个 forEach... 我似乎无法让它工作。编辑:哦,对数组本身起作用。不错。
  • 好东西。我更喜欢array.forEach() 方法。自动创建一个闭包并摆脱所有丑陋的老派for...loop 语法。谢谢!
  • 我认为这里的困惑是closure == scope == function 大部分时间都在 JS 中,所以我猜我的语义会有所不同......
【解决方案2】:

将你的成功回调修改为:

$.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 调用。

【讨论】:

  • 哦,我觉得这看起来更干净一些。
【解决方案3】:

不要使用for循环,而是使用jquery的each..这将解决问题

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

        }
    });
}
}
);

【讨论】:

  • 过去我遇到的唯一问题是 jQuery 的 each 也会遍历对象属性。有一次我遇到了一个令人讨厌的错误,服务器返回了错误,而 jQuery 冻结了页面,试图迭代它不应该迭代的东西。我现在可能因为它而偏执,哈哈。
【解决方案4】:

这会有所帮助

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

【讨论】:

    【解决方案5】:

    试试这个方法,告诉我它是否有效!

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

    【讨论】:

      猜你喜欢
      • 2010-09-18
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 2023-02-18
      • 2013-07-17
      • 2011-08-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多