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

标签 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

最佳答案

为什么不保持简单?

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

更新:

Thanks, recursion does seem to work, but if I attach a done() to getUsers() like so - getUsers(1).done(function() { console.log("all done");}); it doesn't fire. I don't understand. I thought $.ajax() returned a deferred object on its own.

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

有一个简单的方法:

    $.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。递归效果很好,但我猜你想执行最终的“全部下载!”功能。在这种情况下,您需要稍微改进代码。

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 包

我还需要提到我可以看到你真的想坚持使用延迟白很多人只是使用回调而不是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 + 递归解决方案就可以。

关于javascript - 以特定顺序调用的嵌套 AJAX 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44521674/

相关文章:

javascript - componentDidMount 无法从父组件接收 props

javascript - 如何在v-for循环中通过id获取用户名?

javascript - 使用 AJAX 刷新的 Wicket 组件 "wicket:head"部分

javascript - 如何异步运行函数 (XMLHttpRequest)

javascript - 我可以通过索引而不是名称引用 ngRepeat 中的项目吗

javascript - Firebase getDownloadURL 从存储无法设置 Img Src

javascript - 如何使用 javascript/jquery 将大的 html block append 到 Blade 文件?

javascript - 仅在分层 Kendo Ui Grid 的列标题中显示垂直网格线

jquery - 使用 jQuery 访问 css ":after"选择器

jQuery:对元素/插件也使用 .live 方法?