首页 文章

等到所有jQuery Ajax请求都完成了?

提问于
浏览
584

如何使函数等到所有jQuery Ajax请求都在另一个函数内完成?

简而言之,我需要等待所有Ajax请求在执行下一个之前完成 . 但是怎么样?

21 回答

  • 7

    我发现good answergnarf我的自我,这正是我想要的:)

    jQuery ajaxQueue

    //This handles the queues    
    (function($) {
    
      var ajaxQueue = $({});
    
      $.ajaxQueue = function(ajaxOpts) {
    
        var oldComplete = ajaxOpts.complete;
    
        ajaxQueue.queue(function(next) {
    
          ajaxOpts.complete = function() {
            if (oldComplete) oldComplete.apply(this, arguments);
    
            next();
          };
    
          $.ajax(ajaxOpts);
        });
      };
    
    })(jQuery);
    

    然后你可以像这样添加一个ajax请求到队列:

    $.ajaxQueue({
            url: 'page.php',
            data: {id: 1},
            type: 'POST',
            success: function(data) {
                $('#status').html(data);
            }
        });
    
  • 30

    $.when 对我不起作用, callback(x) 而不是 return x 如此处所述:https://stackoverflow.com/a/13455253/10357604

  • 1

    我遇到了这个问题并创建了一个通用的插件jquery_counter来解决它:https://bitbucket.org/stxnext/jquery_counter/

  • -1

    你也可以使用async.js .

    我认为它比$ .when更好,因为你可以合并各种不支持promises的异步调用,如超时,SqlLite调用等,而不仅仅是ajax请求 .

  • 20

    javascript是基于事件的,所以你永远不应该等待,而是设置钩子/回调

    您可以只使用jquery.ajax的成功/完整方法

    或者您可以使用.ajaxComplete

    $('.log').ajaxComplete(function(e, xhr, settings) {
      if (settings.url == 'ajax/test.html') {
        $(this).text('Triggered ajaxComplete handler.');
        //and you can do whatever other processing here, including calling another function...
      }
    });
    

    虽然你应该发布一个伪代码,你的ajax请求被称为更精确...

  • 0

    试试这种方式 . 在java脚本函数中创建一个循环,等待ajax调用完成 .

    function getLabelById(id)
    {
        var label = '';
        var done = false;
        $.ajax({
           cache: false,
           url: "YourMvcActionUrl",
           type: "GET",
           dataType: "json",
           async: false,
           error: function (result) {
             label='undefined';
             done = true;
            },
           success: function (result) {
                label = result.Message;
                done = true;
            }
         });
    
       //A loop to check done if ajax call is done.
       while (!done)
       {
          setTimeout(function(){ },500); // take a sleep.
       }
    
        return label;
    }
    
  • -4

    使用 ajaxStop 事件 .

    例如,假设您在获取100个ajax请求时有一条 loading ... 消息,并且您希望在加载后隐藏该消息 .

    来自jQuery doc

    $("#loading").ajaxStop(function() {
      $(this).hide();
    });
    

    请注意,它将等待在该页面上完成的所有ajax请求 .

  • 1

    jQuery允许您指定是否希望ajax请求是异步的 . 您可以简单地使ajax请求同步,然后其他代码在返回之前不会执行 .

    例如:

    jQuery.ajax({ 
        async: false,
        //code
    });
    
  • 1

    如果你需要简单的东西;一次完成回调

    //multiple ajax calls above
            var callback = function () {
                if ($.active !== 0) {
                    setTimeout(callback, '500');
                    return;
                }
                //whatever you need to do here
                //...
            };
            callback();
    
  • 0

    为了扩展Alex的答案,我有一个带有可变参数和承诺的例子 . 我想通过ajax加载图像,并在加载后在页面上显示它们 .

    为此,我使用了以下内容:

    let urlCreator = window.URL || window.webkitURL;
    
    // Helper function for making ajax requests
    let fetch = function(url) {
        return $.ajax({
            type: "get",
            xhrFields: {
                responseType: "blob"
            },
            url: url,
        });
    };
    
    // Map the array of urls to an array of ajax requests
    let urls = ["https://placekitten.com/200/250", "https://placekitten.com/300/250"];
    let files = urls.map(url => fetch(url));
    
    // Use the spread operator to wait for all requests
    $.when(...files).then(function() {
        // If we have multiple urls, then loop through
        if(urls.length > 1) {
            // Create image urls and tags for each result
            Array.from(arguments).forEach(data => {
                let imageUrl = urlCreator.createObjectURL(data[0]);
                let img = `<img src=${imageUrl}>`;
                $("#image_container").append(img);
            });
        }
        else {
            // Create image source and tag for result
            let imageUrl = urlCreator.createObjectURL(arguments[0]);
            let img = `<img src=${imageUrl}>`;
            $("#image_container").append(img);
        }
    });
    

    已更新,可用于单个或多个网址:https://jsfiddle.net/euypj5w9/

  • 0

    NOTE: 以上答案使用的是撰写本答案时不存在的功能 . 我建议使用 jQuery.when() 而不是这些方法,但我是出于历史目的而离开答案 .

    你可能会使用一个简单的计数信号量,虽然你如何实现它将取决于你的代码 . 一个简单的例子就是......

    var semaphore  = 0,     // counting semaphore for ajax requests
        all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts
    
    semaphore++;
    $.get('ajax/test1.html', function(data) {
        semaphore--;
        if (all_queued && semaphore === 0) {
            // process your custom stuff here
        }
    });
    
    semaphore++;
    $.get('ajax/test2.html', function(data) {
        semaphore--;
        if (all_queued && semaphore === 0) {
            // process your custom stuff here
        }
    });
    
    semaphore++;
    $.get('ajax/test3.html', function(data) {
        semaphore--;
        if (all_queued && semaphore === 0) {
            // process your custom stuff here
        }
    });
    
    semaphore++;
    $.get('ajax/test4.html', function(data) {
        semaphore--;
        if (all_queued && semaphore === 0) {
            // process your custom stuff here
        }
    });
    
    // now that all ajax requests are queued up, switch the bool to indicate it
    all_queued = true;
    

    如果您希望它像{async:false}那样运行,但您不想锁定浏览器,则可以使用jQuery队列完成相同的操作 .

    var $queue = $("<div/>");
    $queue.queue(function(){
        $.get('ajax/test1.html', function(data) {
            $queue.dequeue();
        });
    }).queue(function(){
        $.get('ajax/test2.html', function(data) {
            $queue.dequeue();
        });
    }).queue(function(){
        $.get('ajax/test3.html', function(data) {
            $queue.dequeue();
        });
    }).queue(function(){
        $.get('ajax/test4.html', function(data) {
            $queue.dequeue();
        });
    });
    
  • 6

    当所有ajax加载完成时,我正在使用大小检查

    function get_ajax(link, data, callback) {
        $.ajax({
            url: link,
            type: "GET",
            data: data,
            dataType: "json",
            success: function (data, status, jqXHR) {
                callback(jqXHR.status, data)
            },
            error: function (jqXHR, status, err) {
                callback(jqXHR.status, jqXHR);
            },
            complete: function (jqXHR, status) {
            }
        })
    }
    
    function run_list_ajax(callback){
        var size=0;
        var max= 10;
        for (let index = 0; index < max; index++) {
            var link = 'http://api.jquery.com/ajaxStop/';
            var data={i:index}
            get_ajax(link,data,function(status, data){
                console.log(index)
                if(size>max-2){
                    callback('done')
                }
                size++
                
            })
        }
    }
    
    run_list_ajax(function(info){
        console.log(info)
    })
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    
  • 19

    Alex给出的解决方案很好 . 相同的概念,但使用它有点不同的方式(当预先不知道呼叫的数量)

    http://garbageoverflow.blogspot.com/2014/02/wait-for-n-or-multiple-or-unknown.html

  • 1

    jQuery现在为此目的定义了when function .

    它接受任意数量的Deferred对象作为参数,并在所有这些对象解析时执行一个函数 .

    这意味着,如果你想发起(例如)四个ajax请求,然后在完成后执行一个动作,你可以这样做:

    $.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
        // the code here will be executed when all four ajax requests resolve.
        // a1, a2, a3 and a4 are lists of length 3 containing the response text,
        // status, and jqXHR object for each of the four ajax calls respectively.
    });
    
    function ajax1() {
        // NOTE:  This function must return the value 
        //        from calling the $.ajax() method.
        return $.ajax({
            url: "someUrl",
            dataType: "json",
            data:  yourJsonData,            
            ...
        });
    }
    

    在我看来,它使得语法清晰明确,并避免涉及任何全局变量,如ajaxStart和ajaxStop,这些变量可能会在页面开发时产生不必要的副作用 .

    如果你事先不知道需要等待多少个ajax参数(即你想使用可变数量的参数),它仍然可以完成,但只是有点棘手 . 见Pass in an array of Deferreds to $.when()(也许jQuery .when troubleshooting with variable number of arguments) .

    如果你需要更深入地控制ajax脚本等的失败模式,你可以保存 .when() 返回的对象 - 它是一个包含所有原始ajax查询的jQuery Promise对象 . 您可以在其上调用 .then().fail() 以添加详细的成功/失败处理程序 .

  • 0

    一个小的解决方法是这样的:

    // Define how many Ajax calls must be done
    var ajaxCalls = 3;
    var counter = 0;
    var ajaxCallComplete = function() {
        counter++;
        if( counter >= ajaxCalls ) {
                // When all ajax calls has been done
            // Do something like hide waiting images, or any else function call
            $('*').css('cursor', 'auto');
        }
    };
    
    var loadPersons = function() {
            // Show waiting image, or something else
        $('*').css('cursor', 'wait');
    
        var url = global.ctx + '/loadPersons';
        $.getJSON(url, function(data) {
                // Fun things
        })
        .complete(function() { **ajaxCallComplete();** });
    };
    
    var loadCountries = function() {
        // Do things
        var url = global.ctx + '/loadCountries';
        $.getJSON(url, function(data) {
                // Travels
        })
        .complete(function() { **ajaxCallComplete();** });
    };
    
    var loadCities = function() {
        // Do things
        var url = global.ctx + '/loadCities';
        $.getJSON(url, function(data) {
                // Travels
        })
        .complete(function() { **ajaxCallComplete();** });
    };
    
    $(document).ready(function(){
        loadPersons();
        loadCountries();
        loadCities();
    });
    

    希望可以有用......

  • 0

    在@BBonifield答案的基础上,我编写了一个实用程序函数,以便信号量逻辑不会在所有的ajax调用中传播 .

    untilAjax 是实用程序函数,它在完成所有ajaxCalls时调用回调函数 .

    ajaxObjs 是ajax设置对象 [http://api.jquery.com/jQuery.ajax/] 的数组 .

    fn 是回调函数

    function untilAjax(ajaxObjs, fn) {
      if (!ajaxObjs || !fn) {
        return;
      }
      var ajaxCount = ajaxObjs.length,
        succ = null;
    
      for (var i = 0; i < ajaxObjs.length; i++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
        succ = ajaxObjs[i]['success'];
        ajaxObjs[i]['success'] = function(data) { //modified success handler
          if (succ) {
            succ(data);
          }
          ajaxCount--;
          if (ajaxCount == 0) {
            fn(); //modify statement suitably if you want 'this' keyword to refer to another object
          }
        };
        $.ajax(ajaxObjs[i]); //make ajax call
        succ = null;
      };
    

    示例: doSomething 函数使用 untilAjax .

    function doSomething() {
      // variable declarations
      untilAjax([{
        url: 'url2',
        dataType: 'json',
        success: function(data) {
          //do something with success data
        }
      }, {
        url: 'url1',
        dataType: 'json',
        success: function(data) {
          //do something with success data
        }
      }, {
        url: 'url2',
        dataType: 'json',
        success: function(response) {
          //do something with success data
        }
      }], function() {
        // logic after all the calls are completed.
      });
    }
    
  • 0

    如果你从头开始,我强烈推荐使用$.when() .

    即使这个问题有超过百万的答案,我仍然没有找到任何有用的案例 . 假设您必须处理现有的代码库,已经进行了一些ajax调用,并且不想引入promises的复杂性和/或重做整个事情 .

    我们可以轻松利用jQuery .data.on.trigger 函数,这些函数已成为其中的一部分jQuery永远 .

    Codepen

    关于我的解决方案的好处是:

    • 显然回调究竟取决于什么

    • 函数 triggerNowOrOnLoaded 没有't care if the data has been already loaded or we'还在等待它

    • 将它插入现有代码非常容易

    $(function() {
    
      // wait for posts to be loaded
      triggerNowOrOnLoaded("posts", function() {
        var $body = $("body");
        var posts = $body.data("posts");
    
        $body.append("<div>Posts: " + posts.length + "</div>");
      });
    
    
      // some ajax requests
      $.getJSON("https://jsonplaceholder.typicode.com/posts", function(data) {
        $("body").data("posts", data).trigger("posts");
      });
    
      // doesn't matter if the `triggerNowOrOnLoaded` is called after or before the actual requests 
      $.getJSON("https://jsonplaceholder.typicode.com/users", function(data) {
        $("body").data("users", data).trigger("users");
      });
    
    
      // wait for both types
      triggerNowOrOnLoaded(["posts", "users"], function() {
        var $body = $("body");
        var posts = $body.data("posts");
        var users = $body.data("users");
    
        $body.append("<div>Posts: " + posts.length + " and Users: " + users.length + "</div>");
      });
    
      // works even if everything has already loaded!
      setTimeout(function() {
    
        // triggers immediately since users have been already loaded
        triggerNowOrOnLoaded("users", function() {
          var $body = $("body");
          var users = $body.data("users");
    
          $body.append("<div>Delayed Users: " + users.length + "</div>");
        });
    
      }, 2000); // 2 seconds
    
    });
    
    // helper function
    function triggerNowOrOnLoaded(types, callback) {
      types = $.isArray(types) ? types : [types];
    
      var $body = $("body");
    
      var waitForTypes = [];
      $.each(types, function(i, type) {
    
        if (typeof $body.data(type) === 'undefined') {
          waitForTypes.push(type);
        }
      });
    
      var isDataReady = waitForTypes.length === 0;
      if (isDataReady) {
        callback();
        return;
      }
    
      // wait for the last type and run this function again for the rest of the types
      var waitFor = waitForTypes.pop();
      $body.on(waitFor, function() {
        // remove event handler - we only want the stuff triggered once
        $body.off(waitFor);
    
        triggerNowOrOnLoaded(waitForTypes, callback);
      });
    }
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <body>Hi!</body>
    
  • 1

    看看我的解决方案:

    1.将此函数(和变量)插入到您的javascript文件中:

    var runFunctionQueue_callback;
    
    function runFunctionQueue(f, index, callback) {
    
      var next_index = index + 1
    
      if (callback !== undefined) runFunctionQueue_callback = callback;
    
      if (f[next_index] !== undefined) {
        console.log(index + ' Next function avalaible -> ' + next_index);
        $.ajax({
          type: 'GET',
          url: f[index].file,
          data: (f[index].data),
          complete: function() {
            runFunctionQueue(f, next_index);
          }
        });
      } else {
        console.log(index + ' Last function');
        $.ajax({
          type: 'GET',
          url: f[index].file,
          data: (f[index].data),
          async: false,
          complete: runFunctionQueue_callback
        });
      }
    }
    

    2.使用您的请求创建一个数组,如下所示:

    var f = [
               {file: 'file_path', data: {action: 'action', data: 'any_data}},
               {file: 'file_path', data: {action: 'action', data: 'any_data}},
               {file: 'file_path', data: {action: 'action', data: 'any_data}},
               {file: 'file_path', data: {action: 'action', data: 'any_data}}
            ];
    

    3.创建回调函数:

    function Function_callback() {
      alert('done');
    }
    

    4.使用参数调用runFunctionQueue函数:

    runFunctionQueue(f, 0, QuestionInsert_callback);
    // first parameter: array with requests data
    // second parameter: start from first request
    // third parameter: the callback function
    
  • 1

    如果你想等到文档中的所有ajax请求都完成,无论它们有多少,只需这样使用$.ajaxStop事件:

    $(document).ajaxStop(function () {
          // 0 === $.active
      });
    

    在这种情况下,无需猜测将来可能完成的应用程序中有多少请求 . 在某些情况下,ajax请求可以是函数内部逻辑的一部分,这可能非常复杂(例如调用其他函数),在这种情况下,您可能不会等到所述函数完成其整个逻辑而不是仅等待 ajax 部分完成 .

    $.ajaxStop此处也可以绑定到您认为可能被 ajax 修改的任何 HTML 节点 .

    再次,这个处理程序的目的是知道什么时候没有清除或重置某些东西 active ajax .

    附:如果您不介意使用ES6语法,则可以将 Promise.all 用于已知的 ajax 方法 . 例:

    Promise.all([ajax1(), ajax2()]).then(() => {
     // all requests finished successfully
    }).catch(() => {
     // all requests finished but one or more failed
    })
    

    这里有一个有趣的观点是,它适用于 Promises$.ajax 请求 . 这是jsFiddle展示了最后一个 .

  • 796

    我找到了简单的方法,它使用 shift()

    function waitReq(id)
    {
      jQuery.ajax(
      {
        type: 'POST',
        url: ajaxurl,
        data:
        {
          "page": id
        },
        success: function(resp)
        {
          ...........
          // check array length if not "0" continue to use next array value
          if(ids.length)
          {
            waitReq(ids.shift()); // 2
          )
        },
        error: function(resp)
        {
          ....................
          if(ids.length)
          {
            waitReq(ids.shift());
          )
        }
      });
    }
    
    var ids = [1, 2, 3, 4, 5];    
    // shift() = delete first array value (then print)
    waitReq(ids.shift()); // print 1
    
  • 261

    我的解决方案如下

    var request;
    ...
    'services': {
      'GetAddressBookData': function() {
        //This is the primary service that loads all addressbook records 
        request = $.ajax({
          type: "POST",
          url: "Default.aspx/GetAddressBook",
          contentType: "application/json;",
          dataType: "json"
        });
      },
    
      ...
    
      'apps': {
        'AddressBook': {
          'data': "",
          'Start': function() {
              ...services.GetAddressBookData();
              request.done(function(response) {
                trace("ajax successful");
                ..apps.AddressBook.data = response['d'];
                ...apps.AddressBook.Filter();
              });
              request.fail(function(xhr, textStatus, errorThrown) {
                trace("ajax failed - " + errorThrown);
              });
    

    工作得很好 . 我已经尝试了很多不同的方法,但我发现这是最简单和最可重用的方法 . 希望能帮助到你

相关问题