$q.all in a then Clause - javascript

What is the correct way to use $q.all in a promise chain then clause?
Here is some pseudo-type code to illustrate what I'm trying to do.
function nestedPromise(val)
{
return aPromiseReturningFunction(val)
.then($q.all(val.arrayProperty.map(function(anotherVal)
{
return anotherPromiseReturningFunction({
prop1: anotherVal.prop
});
})));
}
Expectation: if any of the promises returned in the call to $q.all reject, the promise returned by nestedPromise will reject.
Actual: the promise returned by nestedPromise is resolved, even though one of the promises returned in the call to $q.all rejected.
I can't post everything I have tried to get this to work because I feel like I have tried literally everything...catches all over the place, using deferred, etc. I think at one point I got things "working" by using a ton of deferrals and catches, but it was really ugly and it definitely didn't work because I knew what I was doing.
Is it expected behavior for all of the function calls in my $q.all call to run in parallel? That seems to be what is currently happening because even after one promise rejects, the remainder continue to run. For the time being, I can deal with this behavior although it doesn't seem quite right and I'd like to know how to halt execution after the first rejection is encountered.

then() expects a function to be passed to it. You're currently passing another Promise object in here
then($q.all(val.arrayProperty.map(function(anotherVal)
You should instead be doing this
function nestedPromise(val) {
return aPromiseReturningFunction(val)
.then(function() {
return $q.all(val.arrayProperty.map(function(anotherVal) {
return anotherPromiseReturningFunction({
prop1: anotherVal.prop
});
})
});
}

Related

Promises.all() breaking sequential chaining

In the past I've used the jQuery deffered/promises, but I'm trying to move to javascript Promises. I have a function that needs to make several network calls in sequence and then several that can happen in any order, but all need to resolve before moving forward. I start with the sequential calls and they go in order, but then with the results of the second call I need to iterate over those results and make a variable number (at the moment 6) of further calls. I don't care what order those are done in, but do need to wait for all of them to resolve before I proceed. I thought this pattern would work. But it doesn't.
function doLotsOfStuff(){
firstNetworkCall()
.then(function(data){
// do stuff with data
return secondNetworkCall();
})
.then(function(data){
// do stuff with data
var promises = data.map(function(item){
// All of these calls (happens to be 6)
// need to be done before I continue
return thirdIndependentCall(item.Info);
});
// at this point I see [Promise, Promise, ....]
// all are unresolved
return Promise.all(promises);
})
.then(function(results){
// executes immediately after the Promises.all() line
// none of them are resolved
// results is just one unresolved promise
});
}
I can chain the final step onto the Promises.all() like this
return Promise.all(promises)
.then(function(results){
// this works!
})
But if I want to chain more things after that I have to keep stepping them in. Seems like I'm missing some piece of information.
EDIT
I had copied over a typo in my simplified code which isn't in my actual code. The suggestion to add a .catch() in my chain was a good one and I tried it. Now it throws firstNetworkCall(...).then(...).then(...).catch is not a function.
I think the problem is that some of my code (somewhere) is still relying on jQuery.Deffered and that doesn't play well with Promise.
It is good to know that my initial pattern should work -- if I'm consistent with what kind of async handling I'm working with.
Change this:
Promises.all(promises)
to this:
Promise.all(promises)
What you have is throwing an exception (because Promises is not defined which is caught by the .then() and then rejects the promise chain.
This is a classic reason why you should always have a .catch() at the end of your chain because if you were logging that rejection, it would have probably told you what the error was.
If you want to convert any jQuery promises to ES6 promises so you can use .catch() anywhere or to just guarantee consistent behavior, you can wrap them with Promise.resolve() as in:
Promise.resolve(firstNetworkCall()).then(...).catch(...)
or this:
var promises = data.map(function(item) {
// All of these calls (happens to be 6)
// need to be done before I continue
return Promise.resolve(thirdIndependentCall(item.Info));
});
// at this point I see [Promise, Promise, ....]
// all are unresolved
return Promise.all(promises);
And, keep in mind that some newer jQuery versions are more compatible with ES6 promises than others.

Understanding JS Promises

I would like to get a deeper understanding of how Promises work internally.
Therefore I have some sample code:
var p1 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
var p2 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
function chainPromises() {
return p1.then(function(val) {
console.log("p1");
return p2.then(function(val) {
console.log("p2");
return val;
});
});
}
chainPromises().then(function(val) {
console.log(val);
});
Here a link to execute this code.
As you would predict, first p1 is resolved, afterwards p2 and in the end the final then prints the resolv value.
But the API ref states the following:
"then" returns a new promise equivalent to the value you return from
onFulfilled/onRejected after being passed through Promise.resolve
So it would be interesting to know WHEN exactly the "then" function is executed?
Because the final "then" in the code is chained to the chainPromises(), I first thought that
it would execute after the function chainPromises() returns something (in this case another promise).
If this would have been the case the "val" of the final "then" function would be the returned promise.
But instead, the final "then" waits until all promises inside the first "then" which are returned have been resolved.
This absolutely makes sense because in this way, the "then" functions can be stacked, but
I do not really get how this is done, since the API spec. does not really cover what "then" returns and when the "then" functions is executed.
Or in other words, why does the final "then" function wait until all the Promises are resolved inside the chainPromises() function instead of just waiting for the first returned object as the API doc says.
I hope I could make clear what I mean.. :)
About Promise resolution
The thing you're witnessing here is called recursive thenable resolution. The promise resolution process in the Promises/A+ specification contains the following clause:
onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x)
The ES6 promise specification (promises unwrapping) contains a similar clause.
This mandates that when a resolve operation occurs: either in the promise constructor, by calling Promise.resolve or in your case in a then chain a promise implementation must recursively unwrap the returned value if it is a promise.
In practice
This means that if onFulfilled (the then) returns a value, try to "resolve" the promise value yourself thus recursively waiting for the entire chain.
This means the following:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
So for example:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ throw Error(); });
}).then(function(){
alert("This will never run");
});
And that:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ return delay(2000); });
}).then(function(){
alert("This will only run after 2000 ms");
});
Is it a good idea?
It's been the topic of much debate in the promises specification process a second chain method that does not exhibit this behavior was discussed but decided against (still available in Chrome, but will be removed soon). You can read about the whole debate in this esdiscuss thread. This behavior is for pragmatic reasons so you wouldn't have to manually do it.
In other languages
It's worth mentioning that other languages do not do this, neither futures in Scala or tasks in C# have this property. For example in C# you'd have to call Task.Unwrap on a task in order to wait for its chain to resolve.
Let's start with an easy perspective: "chainPromises" returns a promise, so you could look at it this way:
// Do all internal promises
var cp = chainPromises();
// After everything is finished you execute the final "then".
cp.then(function(val) {
console.log(val);
});
Generally speaking, when returning a promise from within a "then" clause, the "then" function of the encapsulating promise will be marked as finished only after the internal "then" has finished.
So, if "a" is a promise, and "b" is a promise:
// "a"'s "then" function will only be marked as finished after "b"'s "then" function has finished.
var c = a.then(function () {
return b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
So the output will be:
B!
Done!
Notice btw, that if you don't "return" the internal promise, this will not be the case:
// "a"'s "then" function will only be marked as finished without waiting for "b"'s "then" to finish.
var c = a.then(function () {
// Notice we're just calling b.then, and don't "return" it.
b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
Here we can't know what would be outputted first. It could be either "B!" or "Done!".
Please check the below example regarding how promises works:
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
console.log('person1: shoe ticket');
console.log('person2: shoe ticket');
const promiseGirlFriendBringingTickets = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ticket');
}, 3000);
});
promiseGirlFriendBringingTickets.then((t) => {
console.log(`person3: show ${t}`);
})
console.log('person4: shoe ticket');
console.log('person5: shoe ticket');
Promise then return promise object, not promise's resolved value. I forked your JsFiddle, and added some of mine try this.
promise.then is executed right after that promise object is resolved.
I do not know how this is done in actual promises libraries, but I was able to re-create this functionality in the following way:
1) each promise has a waitingPromises property;
2) then method returns a new promise, and the original promise's waitingPromises property points to the new promise.
In this way, the chain of .then()s creates a structure that is similar to a linked list or rather a tree (each promise can have several waiting promises). A promise can be resolved only after its 'parent' promise has been resolved. The .then method itself is executed immediately, but the corresponding promise that it creates is resolved only later.
I am not sure this is a good explanation and would love to learn about other possible approaches.
Normally code is synchronous - one statement executes like (fileopen) and there is a guarantee that the next statement will execute immediately afterwards like filewrite()
but in asynchronous operations like nodejs, you should assume that
you have no idea when the operation will complete.
You can't even assume that just because you send out one request first, and another request second, that they will return in that order
Callbacks are the standard way of handling asynchrnous code in JavaScript
but promises are the best way to handle asynchronous code.
This is because callbacks make error handling difficult, and lead to ugly nested code.
which user and programmer not readble easily so promises is the way
You can think of Promise as a wrapper on some background task. It takes in a function which needs to be executed in the background.
The most appropriate place to use a promise is where some code is dependent on some background processing and it needs to know the status of the background task which was executed. For that, the background task itself accepts two callback resolve and reject in order to convey its status to the code which is dependent on it. In layman terms, this code is the one behind it in the promise chain.
When a background task invokes resolve callback with some parameter. it's marking the background operation successful and passing the result of the background operation to the next then block which will be executed next. and if it calls reject, marking it as unsuccessful then the first catch block will be executed.
In your custom promise, you can pass an error obj to the reject callback so that next catch block is aware of the error happened in the background task.

multiple `.then()`s on single angularjs promise -- all use _original_ data

I'm writing an angularjs app relying on promises, and though it's working, I wonder if I could do it more optimally.
At the beginning of the code, I'm creating a promise that goes off to fetch some data. When this is done, I want to run several functions that all use this data. The functions are attached at unrelated parts of the app, so I do not know the order in which they're attached to the promise. They do not need to be done in sequence either.
app.service("Fetch", function ($q){
return function() {
var def = $q.defer();
somelibrary.asynccall(function(error, data){ //callback
if (error) def.reject(error);
else def.resolve(data);
});
return def.promise;
};
});
app.controller("ctrl", function ($scope, Fetch) {
var prom = Fetch();
//somewhere:
prom.then(function(data){$scope.var1 = data["VAR1"];});
//somewhere else:
prom.then(function(data){$scope.var2 = data["VAR2"]});
});
The main disadvantage here is that the later thens are only executed whenever the preceding ones are finished, which is not necessary here.
Also, I need to add return data inside every function(data){...}, otherwise the following then() does not have the data available.
Is there not another way to do this, more apt for this situation?
EDIT: as mentioned by #jfriend00, I was mistaken; in fact the 2 functions both run, in parallel, as soon as the promise is successfully resolved, and they are not chained and therefore not dependent on each other. Thanks for your help
Turning my comment into an answer since it seems to clear up the issue:
With your pattern, the two .then() calls on the same promise are going to get called one after another when the promise is resolved. The second .then() has only to do with the original promise and nothing to do with what happens on the first .then().
These are not chained so the second .then() has no dependency upon what is returned from the first .then() and both will be passed the same data. They are just multiple watchers of the same promise kind of like two event handlers listening for the same event.
The two .then() handlers on the same promise will be called in the order they were attached to the promise and will both be passed the same data.
See these two answers:
Is there a difference between promise.then.then vs promise.then; promise.then
Understanding javascript promises; stacks and chaining
for more info on chaining p.then(...).then(...) vs. branching p.then(...); p.then(...) with promises.
You need parallel execution: $q.all()
$q.all(
function1,
function2,
function3
).then(function(responses) {
console.log(responses);
});

Bluebird, promises and then()

I've been only using bluebird for a few days but I want to go over all my old code and promisify it :)
My problem is that I still don't fully grasp the flow of then() commands.
Consider these two blocks:
A
methodThatReturnsAPromise().then(task2).then(task3);
B
var promise = methodThatReturnsAPromise();
promise.then(task2)
promise.then(task3);
in scenario A task3 will get the result of task2? In B they all get the result of the first promise?
How does the second one differ from running Promise.all from bluebird?
How do these A/B/Promise.all differ when it comes to using the catch method (where do I put it).
Sorry it's a bunch of questions in one.
Welcome to the wonderful world of promises.
How then works in your example
Your assertion in 1 is correct. We can simulate a promise resolving in Bluebird using Promise.resolve on a value.
Let's show this:
Let's get a function that returns a promise:
function foo(){
return Promise.resolve("Value");
}
foo().then(alert);
This short snippet will alert "Value" as we can see.
Now, let's create two more promises, each that alert and return different values.
function task2(e){
alert("In two got " + e);
return " Two ";
}
function task3(e){
alert("In three got " + e);
return " Three ";
}
So, as you can see in your first code it will indeed resolve in a chain, each with the value of the previous part.
In the second example, both task2 and task3 will get the same value and will also execute together (that is, task 3 will not wait for task 2). You can see that here.
Promise.all
Promise.all (or just returning an array from a then fulfillment handler and then using .spread) is used for waiting for multiple results to all complete. On your example, you're hooking on a single result in multiple parts.
The catch
You always put catch where you want the error to be caught. As you would normally in synchronous code. Just remember to always throw in a promise or in promisified code.
in scenario A task3 will get the result of task2? In B they all get the result of the first promise?
Yes.
How does the second one differ from running Promise.all from bluebird?
You do not fetch the results of the (parallel) tasks 2 and 3 into a new promise.
How do these A/B/Promise.all differ when it comes to using the catch method (where do I put it).
Usually you would put it on the end of the chain, except you want to catch a specific error.
promise.catch()
// handles rejections of this promise
promise.then(task2).catch()
// handles rejections from either promise or task2
// if promise is rejected, task2 will not be executed
Promise.all(promise.then(task2), promise.then(task3)).catch()
// handles rejections from any.
// if promise is rejected, neither task2 nor task3 will be executed
// if task2 or task3 throw, the error will immediately handled
// and the other task will not be affected (but its result is unavailable)
You are not getting one simple principle chaining
In first one can be written like
var promise = methodThatReturnsAPromise(),
promise1 = promise.then(task2);
promise1.then(task3);
In second case
var promise = methodThatReturnsAPromise();
promise.then(task2)
promise.then(task3);
Hope this explains the difference b/w the two

$.Deferred: How to detect when every promise has been executed

I have a number of async tasks that need to be completed, so I'm using promises.
I need to detect when each one of the promises has been executed (both resolved and rejected). I must not continue execution until that point.
I was using something like this:
$.when(promise1, promise2, ...).always();
But this code is wrong, because the when method has lazy evaluation, and it returns as soon as one of the promises fails. So the always callback also runs as soon as one of the promises fail.
I was thinking in coding a workaround, but this use case is so common that maybe somebody has done it already, or maybe there's even a way of doing this using just jQuery (if not, it would be nice to add a Promise.whenNonLazy or a Promise.when(promise1, promise2, ..., false) in the future.
Is this possible?
More sophisticated promise libraries have an allSettled() function like Q or Promise.settle like Bluebird.
In jQuery, you could implement such a function yourself as well and extend the $ namespace with it, but that will only be necessary if you need it often and performance-optimized.
A simpler solution would be to create a new promise for each of the ones you are waiting for, and fulfilling them even when the underlying one is rejected. Then you can use $.when() on them without problems. In short:
// using Underscore's .invoke() method:
$.when.apply(null, _.invoke(promises, "then", null, $.when)).done(…)
More stable:
$.when.apply($, $.map(promises, function(p) {
return p.then(null, function() {
return $.Deferred().resolveWith(this, arguments);
});
})).then(…);
You might change the then callbacks a bit to distinguish between fulfilled and rejected results in the final done.
Smithy,
First let's assume your promises are in an array.
var promises = [....];
What you appear to want is .when() applied to some transform of these promises, such that any rejected promise is converted to resolved, whilst being transparent to promises that are already resolved.
The required operation can be written very succinctly as follows :
$.when.apply(null, $.map(promises, resolvize)).done(...);
//or, if further filtering by .then() is required ...
$.when.apply(null, $.map(promises, resolvize)).then(...);
where resolvize is the transform mechanism.
So what should resolvize(), look like? Let's exploit the characteristics of .then() to make the distinction beteween a resolved and a rejected promise, and respond accordingly.
function resolvize(promise) {
//Note: null allows a resolved promise to pass straight through unmolested;
return promise.then(null, function() {
return $.Deferred().resolve.apply(null, arguments).promise();
});
}
untested
With resolvize in some outer scope, it can be made available to be used in a $.when.apply($.map(promises, resolvize)) expression wherever it is needed. This is most likely adequate, without going to the extent of extending jQuery with a new method.
Regardless of how the transform is achieved, you end up with a potential issue; namely knowing for each argument of the .done() callback, whether its corresponding promise was originally resolved or rejected. That's the price you pay for converting rejection to resolution. You may, however, be able to detect the original status from the parameter(s) with which the original promises were resolved/rejected.
That's an interesting property of always - I hadn't expected that behaviour.
I suppose you could use a master, top-level deferred to monitor the states of the main deferreds, which is resolved only once the main deferreds are all either resolved or rejected. Something like:
//set up master deferred, to observe the states of the sub-deferreds
var master_dfd = new $.Deferred;
master_dfd.done(function() { alert('done'); });
//set up sub-deferreds
var dfds = [new $.Deferred, new $.Deferred, new $.Deferred];
var cb = function() {
if (dfds.filter(function(dfd) {
return /resolved|rejected/.test(dfd.state());
}).length == dfds.length)
master_dfd.resolve();
};
dfds.forEach(function(dfd) { dfd.always(cb); });
//resolve or reject sub-deferreds. Master deferred resolves only once
//all are resolved or rejected
dfds[0].resolve();
dfds[1].reject();
dfds[2].resolve();
Fiddle: http://jsfiddle.net/Wtxfy/3/

Categories