This is similar to a question I posted today, but needs the request chained serially. I have two asynchronous requests, where the second request needs the result of first to send the query.
var Db.get = function(key){
var deferred = $q.defer();
//send async req
var req = ....
req.success = function(d){
deferred.resolve(d)
};
req.failure = function(d){
deferred.reject(d)
}
return deferred.promise;
}
var someFn = function(id){
Db.get(id, "abc")
.then(function (d) {
console.log("At 1")
Db.get(d.id, "def")
.then(function (d) {
console.log("At 2")
return d
}, function (e) {
//error
});
}, function (e) {
//error
});
console.log("At 3")
};
I should be thinking it wrongly, as I expect console.log("At 3")
never to be printed in success scenario as I return after console.log("At 2")
. But when I run, in the console I see these order
console.log("At 1")
console.log("At 3")
console.log("At 2")
I was thinking then
would block till it get response from the promise (returned by get() ). so, everything in someFn execute serially. Is this assumption wrong? What is the best way to chain two asynchronous operation, which uses promises, to run serially.
Thanks.
EDIT:
I tried what Ketan suggested Chaining Ajax calls in AngularJs .
var someFn = function(id){
Db.get(id, "abc")
.then(function (d) {
console.log("At 1")
return Db.get(d.id, "def")
}).then(function (d) {
console.log("At 2")
return d
}, function (e) {
//error
return null;
}).then(function (d) {
return d;
});
console.log("At 3")
};
Still, if I make a call like
var res = someFn(1)
console.log(res) /// undefined
chrome terminal shows At 2
after undefined
. I am not sure why the result retuned by someFn
not assigned to res
.
This is similar to a question I posted today, but needs the request chained serially. I have two asynchronous requests, where the second request needs the result of first to send the query.
var Db.get = function(key){
var deferred = $q.defer();
//send async req
var req = ....
req.success = function(d){
deferred.resolve(d)
};
req.failure = function(d){
deferred.reject(d)
}
return deferred.promise;
}
var someFn = function(id){
Db.get(id, "abc")
.then(function (d) {
console.log("At 1")
Db.get(d.id, "def")
.then(function (d) {
console.log("At 2")
return d
}, function (e) {
//error
});
}, function (e) {
//error
});
console.log("At 3")
};
I should be thinking it wrongly, as I expect console.log("At 3")
never to be printed in success scenario as I return after console.log("At 2")
. But when I run, in the console I see these order
console.log("At 1")
console.log("At 3")
console.log("At 2")
I was thinking then
would block till it get response from the promise (returned by get() ). so, everything in someFn execute serially. Is this assumption wrong? What is the best way to chain two asynchronous operation, which uses promises, to run serially.
Thanks.
EDIT:
I tried what Ketan suggested Chaining Ajax calls in AngularJs .
var someFn = function(id){
Db.get(id, "abc")
.then(function (d) {
console.log("At 1")
return Db.get(d.id, "def")
}).then(function (d) {
console.log("At 2")
return d
}, function (e) {
//error
return null;
}).then(function (d) {
return d;
});
console.log("At 3")
};
Still, if I make a call like
var res = someFn(1)
console.log(res) /// undefined
chrome terminal shows At 2
after undefined
. I am not sure why the result retuned by someFn
not assigned to res
.
- 2 See this question that Pawel answered yesterday. stackoverflow./questions/16284403/… – Ketan Commented May 1, 2013 at 2:20
- thanks Ketan. Will try it out. – bsr Commented May 1, 2013 at 2:23
-
Because
someFn
didn't return anything. You need to usesomeFn().then()
and access the value from within the function passed tothen
. Check out this video where I discuss promises: plus.google./events/cljavmi7kpup1fso43k3fkpk2eg – Josh David Miller Commented May 1, 2013 at 7:14
2 Answers
Reset to default 4The place where your having difficulty is that .then
doesn't actually block. It helps you convert synchronous code into asynchronous code, but it doesn't do so for you. Lets start by considering the synchronous code you are trying to re-write. Imagine Db.get
was a synchronous function that returned a value, rather than a promise:
var someFn = function (id){
try {
var d = Db.get(id, "abc");
console.log("At 1");
var d = Db.get(d.id, "def");
console.log("At 2")
return d;
} catch (ex) {
console.log("At 3")
}
};
In this case, when I call someFn
I get a value, not a promise. That is to say the entire function is synchronous.
If we temporarily fast forward a few years and imagine we could use ES6. That would let us re-write your function as:
var someFn = $q.async(function* (id){
try {
var d = yield Db.get(id, "abc");
console.log("At 1");
var d = yield Db.get(d.id, "def");
console.log("At 2")
return d;
} catch (ex) {
console.log("At 3")
}
});
That looks very similar, but this time we have Db.get
returning a promise, and someFn()
will also always return a promise. The yield
keyword actually "pauses" the current function until the promise is fulfilled. This lets it look just like the synchronous code, but it's actually asynchronous.
Rewind to the present, and we need to work out how to write this. The second argument of a .then
call is an error handler, so the exact equivalent to the ES6 example would be:
var someFn = function (id){
return Db.get(id, "abc")
.then(function (d) {
console.log("At 1");
return Db.get(d.id, "def");
})
.then(function (d) {
console.log("At 2");
return d;
})
.then(null, function (ex) {
console.log("At 3")
});
});
Note how each return is only returning from its current function scope. There's no way to force it to jump all the way out of someFn
.
Another interesting experiment to do is:
Db.get('id', 'abc')
.then(function () {
console.log('B');
});
console.log('A');
The above will always log:
A
B
because .then
doesn't block.
I was thinking then would block till it get response from the promise
No. Promises in JS are no transparent, blocking futures, but just a pattern to chain callbacks. The promise is returned before the callback is executed - and At 3
is logged after .then
returns, but before the callback executed. And if you return
in the callback, it doesn't really matter to the outer someFn
.
You rather would use something like
var someFn = function(id){
return Db.get(id, "abc")
.then(function (d) {
console.log("At 1")
return Db.get(d.id, "def");
})
.then(function (d) {
console.log("At 2")
return d
}, function (e) {
//error
});
}
someFn().then(function(d) {
console.log("At 3")
});
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744229995a4564199.html
评论列表(0条)