.each 函数完成后重新加载页面

Reload page after .each function completes

我正在创建一个数组并使用 jquery $.ajax$.each 函数推送 AJAX 查询。我希望在数组完成后页面应该刷新,但是当我尝试这样做时页面会在两者之间刷新。当我对 $.ajax 查询使用 async:false 时,它工作正常,但这会导致性能下降(完成 ajax 查询所花费的时间增加了 5 倍)。有人可以指导我如何去做吗,以下是我输入的代码:

$('#update1').click(function()
{
    $.each(testarray,function(k,valu)
    {
        var count = testarray.length;
        var checkloop = k+1;
        var valkor = "/webresources/api/v3/sites/current/pages/" + valu.value;
        var valkis = valu.checkbox;

        var request =
            $.ajax(
            {
                url: valkor,
                processData: false,
                data: JSON.stringify({ "enabled" : valkis }),

                type: "PUT",    
                contentType: "application/json",
                mimeType: "application/json ",
                headers: { "Authorization": $.cookie('access_token') }
            })

        request.done(function(msg)
        {
            console.log("successfully updated"); 
        })

        request.fail(function(jqXHR)
        {
            console.log("Request failed.");
            console.log("Error code: " + jqXHR.status);
            console.log("Error text: " + jqXHR.statusText);
            console.log("Response text: " + jqXHR.responseText);
        })

        request.then(function()
        {
            location.reload(true);
        })
    }) 
})

以上代码无需等待循环完成即可刷新页面。我什至尝试过循环。请让我知道我错过了什么。

您可以使用 jQuery .when 将操作推迟到 所有 AJAX 请求完成之后。

像这样:

function updateHandler()
{
    var promisesArray = [];
    var successCounter = 0;
    var promise;

    $.each(testarray, function(k, valu)
    {
        var count = testarray.length;
        var checkloop = k+1;
        var valkor = "/webresources/api/v3/sites/current/pages/" + valu.value;
        var valkis = valu.checkbox;

        promise = 
            $.ajax(
            {
                url: valkor,
                processData: false,
                data: JSON.stringify({ "enabled" : valkis }),
                type: "PUT",    
                contentType: "application/json",
                mimeType: "application/json ",
                headers: { "Authorization": $.cookie('access_token') },
            });

        promise.done(function(msg)
        {
            console.log("successfully updated"); 
            successCounter++;
        });

        promise.fail(function(jqXHR) { /* error out... */ });

      promisesArray.push(promise);
    });

    $.when.apply($, promisesArray).done(function()
    {
        location.reload(true);
        console.log("WAITED FOR " + successCounter + " OF " + testarray.length);
    });
}

$('#update1').click(updateHandler);

请参阅 $.when 的文档。

从 jQuery 1.5 开始,调用 $.ajax return 一个 promise。这些对于许多不同的事情很有用(请参阅 this post 了解关于承诺的其他有用的事情),但在我们的例子中,我们希望收集承诺以提供给 $.when 调用,以便推迟一段代码的执行,直到所有 AJAX 请求 return 响应。

$.each循环中,我们定义了$.ajax调用。一旦定义了每一个 - 在每次调用 $.ajax 之后 - 通过网络发送一个请求,浏览器将等待响应。此外,我们为变量中的每个 $.ajax 调用收集关联的 promise。在上面的代码中,我们对这些承诺中的每一个做了两件事:1)我们附加了单独的 doneerror 函数来采取行动 - 特定于单独的请求 - 每次调用完成后; 2) 我们将承诺存储在 promisesArray 中,这样我们才能在 所有 调用完成后才采取行动。

这里要注意的重要一点是这一行:promise = $.ajax(... 不存储 result - 即 AJAX 调用的响应,它存储与 AJAX 调用关联的承诺。

最后,我们将这些承诺交给 $.when,它使用它自己的 done 函数来执行我们想要在所有 AJAX 调用具有 return编辑

上面的解决方案收集了一系列承诺,因为我根据你的问题和你对 testarray 的使用做出的假设是我们无法提前知道需要多少次 AJAX 调用.如果您 确实 知道您将使用多少 AJAX 调用,我们可以从解决方案中删除 promisesArray,在 3 [ 的情况下可能看起来像这样=107=] 调用:

$.when(
    $.ajax( /* args for 1st call */ ).done( /* 1st call success code */ ),
    $.ajax( /* args for 2nd call */ ).done( /* 2nd call success code */ ),
    $.ajax( /* args for 3rd call */ ).done( /* 3rd call success code */ )
    ).done(function()
      {
          location.reload(true);
      });

因为我们可能不知道需要多少次调用,例如由于用户输入,我们需要收集与未知数量的 $.ajax 调用相关的承诺。

在 jQuery 之前支持延迟执行 - 在 jQuery 1.5 之前 - 另一种处理问题的方法 仅在这些其他 N(通常是 AJAX) actions complete 是为了保持一个大的状态变量:要完成 N 个动作,你会产生一个 N 个布尔值数组。当每个动作完成时(AJAX 调用 returned),done 处理程序将做两件事:1)将其标志设置为 true; 2) 检查是否所有 flags 都设置为true,然后采取措施,例如重新加载页面。这是可行的,因为 JavaScript 事件队列处理的单线程性质。

这里还有几点需要注意:

  • 你需要 apply 因为 $.when 需要 deferred 作为单独的参数。
  • 我添加了一个计数器,该计数器在每次 AJAX done 调用时递增,如果您注释掉 location.reload 调用,您应该会看到 - 假设 PUT 调用是成功 - 计数器的值匹配 testarray.
  • 的大小
  • 您应该考虑使用 $.when().done$.when().always() 之间的区别,以确定哪个更适合您自己的代码。
  • 我已经将 $.each$.when 循环的设置拉到一个单独的函数中。这是无关紧要的,您可以将它们保留在 click 中,就像在您的原始代码中一样,它仍然可以工作。
  • 我通过添加一个按钮 update1 作为 id 并点击 https://httpbin/put 作为你的 valkor [=125] 来测试这个=].

通常不要使用 async: false; - 当您发现自己这样做时,请始终后退并寻找其他方法。 jQuery/JavaScript 总是提供一个。

从 AJAX

中取出 'A'

因为 async:false 通常不是一个好主意,因为它会导致各种阻塞行为,这些行为确实会扰乱您的体验,并且对于某些请求,它甚至已被完全弃用:

As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the complete/success/error callbacks.

利用承诺

jQuery 但是支持使用 when() and then() promise 函数,它允许您存储所有请求,异步执行它们,然后在它们全部完成时执行一个函数。

您只需要将每个请求存储到一个数组中即可:

// Store your requests
var requestsToProcess = [];

// Build each request
$.each(testarray, function(k, valu){
       // Push this request onto your array
       requestsToProcess.push(
            $.ajax({
                 url: "/webresources/api/v3/sites/current/pages/" + valu.value,
                 processData: false,
                 data: JSON.stringify({ "enabled" : valu.checkbox }),
                 type: "PUT",    
                 contentType: "application/json",
                 mimeType: "application/json ",
                 headers: { "Authorization": $.cookie('access_token') },
                 done: function(msg){
                      console.log("successfully updated"); 
                 },
                 fail: function(jqXHR){
                      console.log("Request failed.");
                      console.log("Error code: " + jqXHR.status);
                      console.log("Error text: " + jqXHR.statusText);
                      console.log("Response text: " + jqXHR.responseText);
                 }
            })
      );
});

// Now that all of your arrays have been added, process them 
$.when(requestsToProcess).then(function(){
       // Everything has been processed, refresh
       location.reload(true);
});