使用延迟循环和链接Ajax调用

时间:2013-05-03 07:58:30

标签: jquery ajax chaining promise deferred

我已经看到很多关于这个的问题,但似乎没有给出我的案例的正确答案。 我也看到了使用.pipe的答案,但我正在寻找使用.then的答案。

好。我需要做3个ajax调用,让我们说一个允许多个帐户的民意调查应用程序。 需要完成以便帐户可以投票的流程如下:

  1. 登录
  2. 选择选项/ s
  3. 提交
  4. 注销(只需清除cookie,无需发布)。
  5. 假设我有两个帐户:

    var accts = [{user: "acct1", pswd: "1234"},{user: "acct2", pswd: "4321"}];
    

    现在我需要使用jquery的$.each

    来遍历这些帐户
    $.each(accts, function(key,value){
    
    });
    

    我了解到使用$.Deferred可以完美地做到这一点,但是正确实现。

    我想要的是

    --------loop1--------
    login
    select
    vote
    --------loop2--------
    login
    select
    vote
    All Done!.
    

    但是会发生什么(当我尝试console.log时发生的事情)     全部完成!     登录(2)     选择(2)     表决(2)

    所以这是我的代码:

    $.each(data, function(k, v) {
        promise.then(function() {
            return $.post(loginURL, {user: v.username, passwrd: v.password});
        }).then(function(html) {
            if (data > 0) {
                console.log('Logged In!');
                return $.post(pollURL + 'select.php', {id: 143});
            } else {
                console.log('Login Failed.');
                return false;
            }
        }).then(function(data) {
            if (data === 'selected') {
                console.log('Already have a selection.');
                return false;
            } else {
                return $.post(pollURL + 'submit.php');
            }
        }).then(function(data){
             if(data > 1) {
                 Console.log('Successfully Voted.');
             } else {
               // if possible return to the login?
             }
        });
    });
    
    promise.done(function() {
        console.log('All Done. Logged out.');
    });
    

    我做错了什么?。

2 个答案:

答案 0 :(得分:6)

啊,这类似于我挣扎了一段时间的过程。我的解决方案是在jQuery的.apply上使用.when来处理“未知”数量的ajax调用并解决所有问题。

根据您的情况,这并不是您所需要的,但它可能会为您提供有关如何解决问题的一些想法。我试图在你想要做的事情的背景下陈述我的过程,所以

var ajaxArgs = [{id: 1, password: "qwerty"}, {id: 2, password: "zxcvb"}];

function doLogin(id, pass) {
  return $.post("ws/path/here", {id: id, pass: pass});
}

var logins = $.when.apply(null, ajaxArgs.map(function(argSet) { 
  return doLogin(argSet.id, argSet.password); 
});

logins.done(function(){
    var logins = [].concat(arguments);
    logins.forEach(function(login) {
       //do Vote
       //do Logout
    });
});

答案 1 :(得分:1)

我会稍微考虑一下,以简化它。首先,编写一个处理一个用户的函数,返回完成该用户处理的承诺:

function one_user(v){
    return $.post(loginURL, {user: v.username, passwrd: v.password})
    .then(function(data) {
        if (data <= 0) { throw "Login failed."; }
        console.log('Logged In!');
        return $.post(pollURL + 'select.php', {id: 143});
    })
    .then(function(data) {
        if (data === 'selected') {throw 'Already have a selection.';}
        return $.post(pollURL + 'submit.php');
    })
    .then(function(data) {
        if(data > 1) {
            Console.log('Successfully Voted.');
        } else {
           // if possible return to the login?
        }
    })
    .fail(function(e) {console.log("Error: "+e);})
   ;
}

请注意,我已将错误处理替换为最后使用throwfail,这是一种更有承诺的方式来处理“错误”。

现在,您的顶级序列只不过是

$.when(   function() {return one_user(user1);})
    .then(function() {return one_user(user2);})
    .then(function() {console.log("All done!");};

请注意,传递给when / then的函数本身就是返回promises。这是编写基于承诺的代码的常见模式,它允许您将问题分解为单个承诺序列,然后将它们串联起来。

如果user_array中有多个用户,虽然不同的promises框架有不同的处理方式,但一种简单的方法是使用reduce,所以:

user_array.reduce(
    function(prev,cur){
        prev=prev.then(function(){return one_user(cur);});
    }),
    $.Deferred().resolve()
)
.then(function() {console.log("All done!");})
;