Reputation: 3166
I've seen many questions about this but nothing seems to give the right answer for my case.
I've seen also answers that uses .pipe
but I'm looking for an answer that uses .then
.
Okay. I need to do 3 ajax calls, lets say a poll application that allows multiple accounts. The processes that need to be done so that an account can vote are the following.
Let's say I have 2 accounts:
var accts = [{user: "acct1", pswd: "1234"},{user: "acct2", pswd: "4321"}];
Now I need to loop through those accounts using jquery's $.each
$.each(accts, function(key,value){
});
I learned that using $.Deferred
can do this perfectly, but with correct implementation.
What I want is
--------loop1--------
login
select
vote
--------loop2--------
login
select
vote
All Done!.
But what happens is (when i try to console.log
on what is happening)
All Done!
login(2)
select(2)
vote(2)
So here is my code:
$.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.');
});
What am I doing wrong?.
Upvotes: 1
Views: 2311
Reputation:
I would factor this a little differently to simplify it. First, write one function which handles one user, returning a promise to completing the processing for that user:
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);})
;
}
Note that I've replaced the error handling to use throw
together with the fail
at the end, a more promises-like way to handle "errors".
Now, your top-level sequence is nothing more than
$.when( function() {return one_user(user1);})
.then(function() {return one_user(user2);})
.then(function() {console.log("All done!");};
Notice that the functions passed to when/then in the above are themselves returning promises. This is a common pattern in writing promises-based code, which allows you to decompose problems into individual sequences of promises and then string those together.
If you have several users in user_array
, although different promises frameworks have slightly different ways to handle this, an easy approach is to use reduce
, so:
user_array.reduce(
function(prev,cur){
prev=prev.then(function(){return one_user(cur);});
}),
$.Deferred().resolve()
)
.then(function() {console.log("All done!");})
;
Upvotes: 1
Reputation: 5929
ah, this is similar to a process I struggled with for a while. My solution is to use .apply
on jQuery's .when
to process an "unknown" number of ajax calls and resolve them all.
This isn't precisely what you need given your situation, but it might give you some ideas for how to attack your problem. I tried to state my process in the context of what you're trying to do, so
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
});
});
Upvotes: 6