angularjs check if 2 promises have returned - javascript

I have a situation where I want to do things as each individual promise returns, and do something else when Both have returned.
promise1.then(function() { // do stuff })
promise2.then(function() { // do stuff })
$q.all([promise1, promise2]).then(function () {
var dependsOnBoth = promise1.x && promise2.x;
})
I'm wondering whether repeating the promises repeats the calls, and if there is a better way to just make sure that both have finished. Thanks!

Because you are calling then on each promise and again in $q.all on both promises. Each promise gets called twice.
Option one:
You would know, when each promise is resolved. So, don't call then on each promise. Only call it in $q.all.
var promise1 = function(){
var promise1defered = $q.defer();
// promise1 is resolved here.
promise1defered .resolve();
return promise1defered .promise;
}
var promise2 = function(){
var promise2defered = $q.defer();
// promise2 is resolved here.
promise2defered .resolve();
return promise2defered .promise;
}
$q.all([promise1, promise2]).then(function () {
// Both promises are resolved here
})
Option two:
Instead of using $q.all, go for chaining promises.
var promise2 = promise1.then(function(){
// promise1 completed
// Resolve promise2 here
]);
promise2.then(function(){
// promise 2 completed
// Both promise 1 and promise 2 are completed.
});

Then functions resolve in the order that they're added to the promise, so the individual thens will be called before the all.then is called. Each then will only be called once, so that's probably the best way to handle that.
Of course, you could always put all that post-proccessing just in the all route, since it'll happen after both.
Also: don't forget your error callbacks.

Related

passing call back functions to promise.then()

when the call back functions in the myFunction gets called is it when the caller function makes a call like this myFunciton.then ()? Can I say the first one triggers upon myFunction being resolved and second call back function is called upon failure of the myFunction?
myFunciton: function() {
const myPromise = myService.loadData(oParams);
myPromise.then(() => {
//do something
}, () => {
//do something else
});
return myPromise;
}
Promises are a state machine with several potential states: pending(The initial state), fulfilled, and rejected.
When you create a new promise you provide a callback that accepts two parameters both functions resolve and reject respectively. resolve to enter a state of fulfilled, reject to enter a state of rejected, and if the code your promise wraps throws an exception the promise will also enter a state of rejected. Upon being either resolved or rejected your promise will store the returned value for subsequent resolutions.
Now whenever you call myPromise.then, myPromise.catch, or providing a call back function. The promise internally checks it's state.
If the promise is pending, it will queue your handlers, and when a call to reject, resolve, or an exception is thrown it will iterate through the queued handlers and call the appropriate handler(Depending on whether it was resolved or rejected).
Now if the promise is already fulfilled or rejected, the promise will call the appropriate handler asynchronously.
Let's look at your code:
myFunction: function() {
const myPromise = myService.loadData(oParams);
// handlers are queued if myPromise is pending
// function passed to then is called asynchronously if resolved
// callback will be called asynchronously if rejected
myPromise.then(() => {
//do something
}, () => {
//do something else
});
return myPromise;
}
Now your question on when your callbacks will be called.
// This will trigger the execution of myService.loadData
// As pointed out in the comments above your callbacks will either be queued, or
// called asynchronously.
// The value of myPromiseResult will always be a promise(pending, resolved, or // rejected)
const myPromiseResult = myFunction();
// Here's the cool part, since promises are essentially a state machine
// every subsequent callback will yield the same result
myPromiseResult.then(() => {
// if the callback pass to myPromise.then is called within myFunction
// this will be called as well, and if you were passing a result
// it would have the same result as well
}, () => {
// if the error callback pass to myPromise within myFunction was called
// then this will be called as well, and as mentioned above would have
// been passed the same result as well.
});
With that code, the first promise that will be resolved will be the one inside "myFunciton" function. Then, if you used something like myFunciton.then(), it will be resolved in second place.
I hope i could help you.

Returning a promise inside another not working [duplicate]

I want to fulfill a promise with some other promise. The point is that I really want to get access to the (still pending) second promise as soon as the first promise is fulfilled. Unfortunately, I only seem to be able to get the second promise's resolution value once both both promises are fulfilled.
Here's the use case that I have in mind:
var picker = pickFile();
picker.then( // Wait for the user to pick a file.
function(downloadProgress) {
// The user picked a file. The file may not be available just yet (e.g.,
// if it has to be downloaded over the network) but we can already ask
// the user some more questions while the file is being obtained in the
// background.
...do some more user interaction...
return downloadProgress;
}
).then( // Wait for the download (if any) to complete.
function(file) {
// Do something with the file.
}
)
The function pickFile displays a file picker where the user may pick a file either from their own hard drive or from a URL. It returns a promise picker that is fulfilled as soon as the user has picked a file. At this point, we may still have to download the selected file over the network. Therefore, I cannot fulfill picker with the selected file as resolution value. Instead, picker should be fulfilled with another promise, downloadProgress, which in turn will eventually be fulfilled with the selected file.
For completenes, here's a mock implementation of the pickFile function:
function pickFile() {
...display the file picker...
var resolveP1 = null;
var p1 = new Promise(
function(resolve, reject) {
resolveP1 = resolve;
}
);
// Mock code to pretend the user picked a file
window.setTimeout(function() {
var p2 = Promise.resolve('thefile');
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
}, 3000);
return p1;
}
The problem in the marked line is that I would like to fulfill the promise p1 with the new promise p2, but I only know how to resolve it. The difference between fulfilling and resolving is that resolving first checks if the supplied value p2 is again a promise. If it is, then fulfillment of p1 will be deferred until p2 is fulfilld, and then p1 will be fulfilled with p2's resolution value instead of p2 itself.
I could work around this issue by building a wrapper around p2, i.e. by replacing the line
resolveP1(p2); // <--- PROBLEM: I actually want to *fulfill* p1 with p2
from the second code example by
resolveP1({promise: p2});
Then, in the first code example, I'd have to replace the line
return downloadProgress;
by
return downloadProgress.promise;
But this seems like a bit of a hack when all I really want to do is just fulfill (instead of resolve) a promise.
I'd appreciate any suggestions.
There doesn't seem to be a solution apart from the workaround I already described in the question. For future reference, if you want to fulfill (rather than resolve) a promise p with a value val, where val is another promise, then just calling the promise resolution function for p with argument val won't work as expected. It would cause p to be "locked in" on the state of val, such that p will be fulfilled with val's resolution value once val is fulfilled (see spec).
Instead, wrap val in another object and resolve p with that object:
var resolveP; // Promise resolution function for p
var p = new Promise(
function(resolve, reject) {
resolveP = resolve;
}
);
function fulfillPwithPromise(val) { // Fulfills p with a promise val
resolveP({promise: val});
}
p.then(function(res) {
// Do something as soon as p is fulfilled...
return res.promise;
}).then(function(res) {
// Do something as soon as the second promise is fulfilled...
});
This solution works if you already know that val is a promise. If you cannot make any assumptions about val's type, then you seem to be out of luck. Either you have to always wrap promise resolution values in another object, or you can try to detect whether val has a field then of type "function" and wrap it conditionally.
That said, in some cases the default behavior of promise resolution may actually have the desired effect. So only use the workaround described above if you are sure that you want to fulfill instead of resolve the first promise with the second one.
Although different people use different terms, in common terminology, "fulfill" means to put a promise in the "success" state (as opposed to "reject")--the state that will trigger then then handlers hanging off it.
In other words, you cannot "fulfill" a promise with a promise. You can fulfill it with a value. (By the way, the term "resolve" is usually meant as either of fulfilling or rejecting.)
What you can do is return a promise from a .then handler and that will have the effect of essentially replacing the original promise with the returned promise.
Here is a simple example of doing that:
asyncTask1 . then(asyncTask2) . then(processData)
where asyncTask1 is a promise, and asyncTask2 is a function which returns a promise. So when asyncTask1 is fulfilled (done successfully), then asyncTask2 runs, and the promise returned by the .then is "taken over" by the promise asyncTask2 returns, so that when it finishes, the data can be processed.
I can do something similar by calling Promise.resolve with a promise as parameter. It's a bit of a misnomer, because I'm not resolving the promise in the technical sense. Instead, the new promise created is "inhabited" by the promise I passed in. It's also useless, because using the result is exactly the same as using the promise I passed in:
Promise.resolve(asyncTask2)
behaves exactly the same as
asyncTask2
(assuming asyncTask2 is already a promise; otherwise Promise.resolve has the effect of creating a promise which is immediately fulfilled with the passed in value.)
Just as you can pass a promise to Promise.resolve, you can pass a promise to the resolve function provided to you as a parameter of the promise constructor callback. If the parameter you pass to resolve is a non-promise, the promise immediately fulfills with that value. However, if the parameter you pass to resolve is another promise, that promise "takes over the body" of the promise you are constructing. To put it another way, the promise you are constructing starts to behave exactly as the the promise passed to resolve.
By "behave exactly" I mean, if the promise you pass in to resolve is already fulfilled, the promise you are constructing is instantly fulfilled with the same value. If the promise you pass in to resolve is already rejected, the promise you are constructing is instantly rejected with the same reason. If the promise you pass in to resolve is not resolved yet, then any then handlers you hang off the promise you are constructing will be invoked if and when the promise you pass to resolve is resolved.
Just as it is confusing that Promise.resolve may result in a promise which is not actually resolved, it is similarly confusing that calling the resolve function handed to you as a parameter to the promise constructor may not actually resolve the promise being constructed if you call it with an unresolved promise. Instead, as I've said a couple of times now, it has the effect of putting the promise being constructed in a state of total congruence with the promise passed to resolve.
Therefore, unless I am missing the point of your question, pickfile could be written as
function pickFile() {
return new Promise(function(resolve, reject) {
...display the file picker...
// Mock code to pretend the user picked a file
window.setTimeout(function() {
resolve('thefile');
});
}
I didn't really understand your question clearly, so this might not be what you want. Please clarify if you care to.
Found a similar solution in the process of moving away from Angular's $q to the native Promise feature. Promise.all could be an option (in cases of independent parallel async tasks) by passing around an appropriate object, or something decorated with the state, passing it off to whatever is ready when appropriate. In the Promise.all sample below note how it recovers in one of the promises--took me awhile to realize how to redirect the result of a chain. The result of the all is just the last promise's return. While this doesn't answer the question's title, using return Promise.reject(<an-object-including-a-promise>) (or resolve) gives a series and/or group of async tasks shared access and control along the way. In the case of picking, downloading then working with a file I'd take out the progress-event handling then do: pickFile.then(download,orFailGracefully) with downloadProgress handled within the download onResolve handler (download-progress doesn't appear to be an async task). Below are related experiments in the console.
var q = {
defer: function _defer(){
var deferred = { };
deferred.promise = new Promise(function(resolve, reject){
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
}
};
var communityThatCares = q.defer();
communityThatCares.promise.then(function(someGood){
console.log('someGood', someGood);
return someGood;
}, function(someBad){
console.warn('someBad', someBad);
return someBad;
});
(new Promise(function(resolve, reject){ communityThatCares.about = 'communityThatCares'; setTimeout(resolve,1000, communityThatCares); }))
.then(
function(e){
console.log(3,e); return e.resolve(e);
}, function(e){
console.warn(3, e); return e.reject(e);
});
var todo = {
find:'swan'
};
var greaterGood = [(
(new Promise(function(res,rej){ res(todo); })).then(function(e){ e.stuff = 'things'; return e; }),
(new Promise(function(res,reject){
reject(todo);
})).then(function(e){ return e; }
,function(e){
console.warn(1,e);
e.recover = 'uh oh';
return Promise.resolve(e);
}).then(function(e){ console.log(2,e); return e; }),
(new Promise(function(res,rej){ res(todo); })).then(function(e){ console.log(1,e); e.schedule = 'today'; return e; },function(e){ console.warn(1,e); return e; }).then(function(e){ console.log(2,e); return e; }))
];
var nkay = Promise.all( greaterGood )
.then(function(todo){
console.log('all',todo[0]); return todo;
}, function(todo){
console.warn('all',todo[0]); return todo;
});

Using $q, struggling to get rejections to cascade in AngularJS

I have a series of promises, on dependant on the other completing and want to "then" them together to get a single promise representing the completion of the whole sequence. This seems to work fine however I can't seem to get any failures to cascade down the promise chain as it appears they are supposed to do from the documentation, here's a code sample to illustrate what I'm struggling with:
var deferred = $q.defer();
deferred.resolve();
var resolvedPromise = deferred.promise;
var rejectedPromise = $q.reject('rejected');
var aPromise = resolvedPromise.then(rejectedPromise);
aPromise.then(function () {
console.log('promise fulfilled');
}, function () {
console.log('promise rejected');
});
The same in Plunker
I would expect "promise rejected" to be logged, but instead I get "promise fulfilled". Any ideas how I can achieve my desired behaviour?
JBNizet's answer is good but I think something needs to be clarified.
The then function promises have will ignore anything passed to it other than a function. So when you have code that does:
myPromise.then(otherPromise)
The whole otherPromise part is completely ignored. The rationale for this that since Promises/A+ does not specify a catch method you needed to be able to do .then(null, errHandler) to handle errors without changing the promise value itself if it resolved.
That's because you don't return the rejected promise from the success callback of the resolved one:
var aPromise = resolvedPromise.then(function() {
return rejectedPromise;
});
Also note that, to construct a resolved promise, you could simply use
var resolvedPromise = $q.when('result');

Angularjs, wait for a nested promise

I have 3 services that return 3 promises, but the third needs the data from the second, so I call it inside the second. I want to wait for all the three promises to be solved, this is the way that I implemented, but doesn't work (waits only for the first and the second).
var promise1, promise2, promise3;
promise1 = service1();
promise2 = service2();
promise2.then(function (data) {
promise3= service3(data);
});
$q.all([ promise1, promise2, promise3]).then(function success() {
//somehing
});
You can assign the second promise's then() callback with a returned promise from the third service.
var promise1, promise2, promise3;
promise1 = service1();
promise2 = service2();
promise3 = promise2.then(function (data) {
return service3(data);
});
$q.all([ promise1, promise2, promise3]).then(function success() {
//somehing
});
Have you tried to nest your promise 2 inside promise 1, and then put your final resolve inside the promise 3 delegate?
That's pretty slick code and I'm certainly no expert, but have had to wait to accomplish things on other service calls and have had to do things like that.

How to correctly chain promises in complex resource loading sequence?

In angular code, I have a chained promise like this:
// a function in LoaderService module.
var ensureTypesLoaded= function(){
return loadContainerTypes($scope).then(loadSampleTypes($scope)).then(loadProjectList($scope)).then(loadSubjectTypes($scope));
}
Each of these functions return a promise, that loads things from a resource and additionally modifies $scope on error and success, e.g.:
var loadProjectList = function ($scope) {
// getAll calls inside a resource method and returns promise.
return ProjectService.getAll().then(
function (items) {
// succesfull load
console.log("Promise 1 resolved");
$scope.projectList = items;
}, function () {
// Error happened
CommonService.setStatus($scope, 'Error!');
});
};
I intent to use in in a code in a controller initialziation as such:
// Part of page's controller initialization code
LoaderService.ensureTypesLoaded($scope).then(function () {
// do something to scope when successes
console.log("I will do something here after all promises resolve");
}, function () {
// do something when error
});
However, this does not work as I'd like to. Ideally message "I will do something here after all promises resolve" must appear after all promises resolve. Instead, I can see that it appears earlier than messages from resolved promises within functions that are listed ensureTypesLoaded.
I would like to create a function ensureTypesLoaded such, that:
it returns a promise that is resolved when all chained loads are resolved;
if any of "internal" promises fail, the function should not proceed to next call, but return rejected promise.
obviously, if I call ensureTypesLoaded().then(...), the things in then() must be called after everything inside ensureTypesLoaded is resolved.
Please help me with correct building of chained promises.
I thinks that problem is in your loadProjectList function. Because .then() should receive function which is called at resultion time. Usually is function returning chain promise.
But in your case you call all load immediately in parallel. It's little complicated with $scope passing. But I think your code should appear like this
//this fn is called immediatly on chain creation
var loadProjectList = function ($scope) {
//this fn is called when previous promise resolves
return function(data) {
//don't add error handling here
ProjectService.getAll().then(...)
}
}
This cause serial loading as you probably want. (just notice: for parallel excution in correct way $q.all is used)
Finally you should have error handler only in ensureTypesLoaded, not in each promise.

Categories