【问题标题】:synchronous jquery $.ajax without locking IE?没有锁定 IE 的同步 jquery $.ajax?
【发布时间】:2012-04-20 08:55:52
【问题描述】:

花了一些时间试图实现这一点,并有一个我认为在 Firefox 中运行良好的解决方案,但是在 IE 中测试时发现使用 async: false 会导致浏览器被锁定(停止响应并且似乎已冻结) 在通话期间。

要求基本如下。我提供了一系列用户可以检查的复选框。在特定时间,我调用我的函数“selectedSeriesData()”,该函数用于一个接一个地向我的服务发送请求,获取请求的数据。我特别选择使用同步,以便在方法执行时向浏览器输出状态消息和警告。

例如。 “加载数据 1/3”,然后“加载数据 2/3”,“加载数据 3/3”

当然,我现在知道这会锁定某些浏览器,因此在 IE 中的体验不仅会锁定浏览器,而且我尝试显示的任何消息都不会显示。是否有任何简单的 doEvents 之类的动作,我可以在每次 ajax 调用后调用,或者只是重组我的 ajax 调用的问题。如果是这样的话,根据我的要求有什么实施建议吗?

以下是代码的简化摘录,以供参考。

function selectedSeriesData() {

    var seriesData = [];
    var index = 0;

    $.each($("input[name='idCheckBox']:checked"), function () {

        var id = $(this).val();

        $("#loadingMessage").text("Loading " + id + "...");

            $.ajax({
                type: 'POST',
                async: false,
                url: '<%: loadSeriesDataPath %>',
                dataType: 'json',
                data: {
                    Id: id
                },
                success: function (data) {
                    seriesData[index] = data;
                    index++;
                },
                error: function (xhr, ajaxOptions, error) {
                    $("#warnings ul").append('<li>A communication error occured while attempting to load data for the series.</li>');

                }
            });
        }
    });
    return seriesData;
}

【问题讨论】:

  • OptimusCrime,当我说锁定时,我的意思是浏览器实际上停止响应,并且只有在循环完成执行后才开始响应。所以对于使用 IE 的最终用户来说,看起来浏览器已经崩溃了。
  • 你能提供jsFiddle的例子吗?
  • 为什么需要同步 XHR?!
  • 您已经发现了 AJAX 调用是异步的原因。同步调用可以并且将会锁定浏览器,因为 JS 引擎会等待调用完成。为什么不使用异步调用?
  • ThiefMaster,我解释了原因,我在问我应该怎么做,因为这显然是错误的方法。

标签: jquery ajax asynchronous


【解决方案1】:

您可以使用jQuery Deferred objects 继续使用异步请求,然后在所有请求都完成后“加入”结果。

function selectedSeriesData(cb) {
    var reqs = [];
    $("#loadingMessage").text("Loading...");
    $("input[name='idCheckBox']:checked").each(function () {
        var id = $(this).val();

        var req = $.ajax({
            type: 'POST',
            url: '<%: loadSeriesDataPath %>',
            dataType: 'json',
            data: {
                Id: id
            },
            error: function(xhr, ajaxOptions, error) {
                $("#warnings ul").append('<li>A communication error occured while attempting to load data for the series.</li>');

            }
        });
        reqs.push(req);
    });
    $.when(reqs).done(function() {
        cb($.makeArray(arguments));
    });
}

现在您只需将回调传递给您的函数,该函数将在所有成功完成后立即接收包含来自 AJAX 请求的所有结果的数组。

注意:$.when 上的文档并不清楚它是否接受包含延迟的单个数组。如果它不起作用,请尝试 $.when.apply($, reqs) 而不是 $.when(reqs)

【讨论】:

  • 听起来棒极了。我马上去看看!
  • Deferred 对象没有任何运气,不能 100% 确定它是否适合我的问题。我确实提出了一个我现在发布的异步解决方案,如果社区同意与否,我会感兴趣。
【解决方案2】:

我认为我的问题的最佳答案是......你做错了。正如建议的那样,我对 $.when 没有任何运气(也许是由于我对它的理解),所以我自己想出了以下答案。

基本上,使用回调来实现一种递归排队。这对你们所有人来说可能听起来很明显,但对我来说它是新的,我认为那里有经验的 jqueryer 会同意我的实现(如果我做得对,请告诉我!)

首先,建立一个请求数组,而不是遍历我的复选框并发出 ajax 请求。这消除了从原始方法返回结果的需要,并开始了最终导致所需结果的方法执行链。

function selectedSeriesData() {

    var requests = [];

    $.each($("input[name='somethingCheckBox']:checked"), function () {

        var id = $(this).attr('value');

        var request = {
            id: id
        };

        requests.push(request);

    });

    loadRequests(requests);
}

从请求数组开始调用 loadRequests,它初始化一个递归回调实现以从我的服务加载数据。

function loadRequests(requests)
{
    $("#loader").show();
    var seriesData = [];
    loadRequestAt(requests, 0, seriesData);
}

调用的递归方法是 loadRequestAt,它跟踪请求数组、加载此迭代的特定索引以及调用方法时添加的 seriesData。 Anon 方法 Success 用于构建我的 seriesData,Error 用于报告错误,而 Complete 最重要的是用于开始下一次请求迭代,或者如果所有请求都已发出,则将结果呈现到屏幕上。

function loadRequestAt(requests, loadAtIndex, seriesData) {
    var currentRequest = requests[loadAtIndex];

    $("#loadingMessage").text("Loading " + currentRequest.id + "...");

    $.ajax({
        type: 'POST',
        url: '<%: loadSeriesDataPath %>',
        dataType: 'json',
        data: {
            Id: currentRequest.id
        },
        success: function(data) {
            seriesData.push(data);
        },
        error: function(xhr, ajaxOptions, error) {
            $("#warnings ul").append('<li>A communication error occured while attempting to load ' + currentRequest.id'.</li>');
        },
        complete: function() {
            var nextIndex = loadAtIndex + 1;
            if (nextIndex < requests.length) {
                loadRequestAt(requests, nextIndex, seriesData);
            } else {
                $("#loader").hide();
                renderResults(seriesData);
            }
        }
    });
}

重要的经验教训。使用 AJAX(异步 JavaScript 和 XML)时,请务必使用异步调用。一定要使用提供的匿名回调方法来实现渐进式排队功能(我确定有一个可接受的名称,但我不确定)。希望我的学习步骤可以帮助那些不熟悉 jquery 和 ajax 调用的人。谢谢!

【讨论】:

    猜你喜欢
    • 2023-03-25
    • 2021-11-13
    • 2012-01-10
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 2012-08-11
    • 1970-01-01
    相关资源
    最近更新 更多