嵌套的AJAX调用以特定顺序调用

时间:2017-06-13 12:33:20

标签: javascript jquery ajax

我尝试过this questionthis,但我似乎无法弄清楚如何使我的要求有效。

我想在一个循环中多次调用https://reqres.in/api/users。此AJAX调用仅返回虚拟用户的第一页。在我获得第一页后,我想打电话给下一页。

这是我的代码:

$(document).ready(function() {

    function getMoreUsers() {
        var def = $.Deferred();
        var requests = [];
        for (var j=2; j<=4; j++) {
            console.log("getting info for page # " + j);
            requests.push(
                $.ajax("https://reqres.in/api/users?page=" + j).done(function() {
                    console.log("got info for page # " + j);
                    def.resolve();
                })
            );
        }
        return def.promise();
    }   

    function getAllUsers() {
        var def = $.Deferred();
        var requests = [];
        for (var i=0; i< 2; i++) {
            console.log("iteration # " + i);
            requests.push(
                $.ajax("https://reqres.in/api/users").done(function(data) {
                    console.log("got first page info");
                    getMoreUsers();
                    def.resolve();
                })
            );
        }
        return def.promise();
    }

    getAllUsers().done(function() {
        console.log("all completed");
    });
});

我得到的输出是:

iteration # 0 
iteration # 1 
got first page info 
getting info for page # 2 
getting info for page # 3 
getting info for page # 4 
all completed 
got first page info 
getting info for page # 2 
getting info for page # 3 
getting info for page # 4 
got info for page # 5

但是,我想要这个:

iteration # 0
got first page info
getting info for page # 2
got info for page # 2
getting info for page # 3
got info for page # 3
getting info for page # 4
got info for page # 4
iteration # 1
got first page info
getting info for page # 2
got info for page # 2
getting info for page # 3
got info for page # 3
getting info for page # 4
got info for page # 4
all completed

当我循环到4时,我甚至不理解page # 5如何出现在输出中,它来了6次,如下所示:

enter image description here

2 个答案:

答案 0 :(得分:1)

第二个你不需要延期。递归更好。

            $(document).ready(function () {

                var apiUrl = "https://reqres.in/api/users";
                var baseAjaxConfig = {
                    method: "GET",
                    url: apiUrl
                };
                var page = 1;
                var maxUsers = 5; //CHANGE THIS ACCORDING TO WHAT YOU WANT
                function getUser(page) {
                    var ajaxConfig = $.extend({}, baseAjaxConfig, {data: {page: page}});
                    $.ajax(ajaxConfig).done(function () {
                        (page < maxUsers) && getUser(page+1);
                    }).fail(function () {
                        (page < maxUsers) && getUser(page+1);
                    });

                }

                getUser(page);
            });

这是一个小提琴==&gt; https://jsfiddle.net/tonysamperi/5j8166be/

答案 1 :(得分:1)

为什么不保持简单?

var getUsers = function(i) {
    $.ajax("https://reqres.in/api/users?page=" + i).done(function() {
        if (i < 5) {
            getUsers(i + 1);
        }else{
            //done!
        }
    });
}    
getUsers(1);

更新

  

谢谢,递归看起来确实有效,但是如果我将done()附加到getUsers()之类的话 - getUsers(1).done(function(){console.log(“all done”);});它不会开火。我不明白。我以为$ .ajax()自己返回了一个延迟对象。

我的代码只是一个提示,您如何解决您的问题。无论如何,让我来帮助你。

有简单的方法:

    $.ajax("https://reqres.in/api/users?page=" + i).done(function() {
        // use data, store it in array outside or draw HTML
        if (i < 5) {
            getUsers(i + 1);
        }else{
            //done! do something when finished
            // iAmDoneHere()
        }
    });

但是如果你想使用deferred:那么$.ajax会返回Deferred。递归效果很好,但我想你想要exectule final“全部下载!”功能。在这种情况下,您需要稍微改进一下代码。

var pages = [];
var getUsers = function(maxPage, currentPage, deferred) {
    var deferred = false;
    if (!currentPage) {
        // this is the top function call
        // the top call without recursion
        var currentPage = 1;
        deferred = $.Deferred();
    }
    $.ajax(..."?page="+currentPage).done(function(){
        // we got page info, great! what next?
        pages.push({insert the page data here});

        // what next?

        // if there is more to fetch, do it
        if (i < maxPage) {
            // pass maxPage, page to parse + 1 and top deferred
            var subd = getUsers(maxPage, i + 1, deferred);
        }else{
            // if there is more to parse, do it
            // we downloaded the final page
            // so now we can finally resolve the top deferred
            // which was passed in every recursion
            deferred.resolve(); 
        }
    }
    return deferred;
}    

getUsers(10).done(function(){
   // executed when all pages are done
   // results are stored in pages[] 
});

最糟糕的部分是我已经写了很多,这仍然可以改进(我应该pages[]变量作为全局/父范围)

我想说管理异步回调非常简单,但是进行简单的回调更为先进。

如果你在更大的项目上工作,你可以写出或使用一些能为你完成所有这些工作的课程而不用担心任何事情,例如

var getUsers = function(maxPages) {
  var d = $.Deferred();
  var pages = [];
  var queue = new Queue();
  for (var i=0;i<maxPages;i++) {
    queue.push(function(page){
      return $.ajax(.."?page="+page).done(function(){pages.push(page);});
    }, i);
  }
  queue.run(function(){
    d.resolve(pages);
  });
  return d;
}
getUsers(10).done(function(pages){/* all pages in "pages" */});

这是以正确的方式完成的,如果您想在其他地方使用队列,则不会重复您的代码。还有很多准备好的npm套餐

另外我需要提一下,我可以看到你真的想要坚持延迟白人,只需使用callbacks而不是deferredpromises来完成简单的任务。

// Deferred way
function doJob(arg1, arg2) {
   var d = $.Deferred();
   window.setTimeout(function(){
      d.resolve();
   }, 100);
   return d;
}    

// Callback way
function doJob(arg1, arg2, callback) {
   window.setTimeout(function(){
      callback();
   }, 100);
}

保存代码有点复杂,但为开发人员提供的层和选项更少。两种方法都很好。我说所有这些都是为了让你知道有很多方法,并且没有明确的答案如何回答你的问题。

我会选择一些Queue,回调解决方案是最简单的,Deferred / Promise +递归解决方案没问题。