Angularjs, wait for a nested promise - javascript

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.

Related

Promises: combine single resolve methods and Promise.all()

I have multiple promises fetching different assets. I want to achieve:
Executing some code first to handle some of these promises via then().
When everything is resolved/fetched, executing some code that launches my app via Promise.all().then().
I need to make sure 1 is excuted before 2. It does seem to work from what I have tested.
// handle promises one by one
promise1.then(results => {});
promise2.then(results => {});
// common process that should come after the above then()s
Promise.all([promise1, promise2])
.then(results => {});
But can I rely on it? Are "single" then() always executed before a then() on Promise.all()?
While Promise.all is stalled because it waits for all the promises to finish, there is no guarantee that it will resolve after the .then call on the promise that resolves last.
Instead you should try creating new promises from the .then calls.
// handle promises one by one
const promise3 = promise1.then(results => {});
const promise4 = promise2.then(results => {});
// common process that should come after the above then()s
Promise.all([promise3, promise4])
.then(results => {});
This way you can guarantee that the Promise all will resolve after the then calls
You can around by using Async/await. With waiting for each promise, you can write code to process data at the end.
Example:
(async () => {
const responses = [];
await new Promise((res) => res("promise1")).then((res) => {
console.log("From promise1 first then");
responses.push(res);
});
// Code at the end to do after all promises
console.log("Coming from second");
console.log("Responses:", responses);
})();

JS: async/await for multiple promises

If I have promise running synchronously, how do I want for both of them to finish? Doesn't await only work for a single Promise?
async function testing() {
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve("one"), 1000)
});
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve("two"), 1000)
});
// how do I await both of these?
}
You can use Promise.all to wait for both of them at once
const [result1, result2] = await Promise.all([promise1, promise2]))
If you want to resolve all promises then you can do two things which are Promise.allSettled() or Promise.all(). So based on your need, choose one.
The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.
Promise.allSettled([
Promise.resolve('promise1'),
Promise.reject('promise2')
]).then(console.log)
It is typically used when you have multiple asynchronous tasks that are not dependent on one another to complete successfully, or you'd always like to know the result of each promise.
In comparison, the Promise returned by Promise.all() may be more appropriate if the tasks are dependent on each other / if you'd like to immediately reject upon any of them rejecting.
Promise.all([Promise1, Promise2])
.then(result) => {
console.log(result)
})
.catch(error => console.log(`Error in promises ${error}`))
Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
You can use promise.all or promise.allSettled
If your use case is like if any one of the request fails then operation needed to be fail means then its good to use promise.all
If you need to keep waiting for all, regardless of any in between request fails or not then you need to use promise.allSettled.
But both of these wont ensure serializability. If you need to ensure serializable i would prefer to use for await loop and use promise.resolve inside it.

two Promise.all() on the same page

I have two Promise.all() on the same page like this:
// promiseGroup1
Promise.all([promise1, promise2, promise3]).then(function(values1) {
doStuff1(values1)
})
// promiseGroup2
Promise.all([promise4, promise5, promise6]).then(function(values2) {
doStuff2(values2)
})
I want everything to start ASAP, and to let promiseGroup1 to continue to doStuff1() if promiseGroup1 finishes first, but doStuff2() to wait doStuff1()to finish. How can I implement this?
If you want one to wait for the other, then you don't want them to be separate async Promises. Instead of trying to force them to be synchronous, why not just include all the promises in one Promise.all and then call doStuff1() and doStuff2() in sequence in the same .then callback?
Keep in mind that the individual Promises you're passing to Promise.all will begin running as soon as they're created; they won't wait to run for Promise.all. So it's not like putting them in different groups changes which resolve first.
To clarify, what you're asking for is equivalent to this:
Promise.all([promise1, promise2, promise3, promise4, promise5, promise6]).then(function(values1) {
doStuff1(values1);
doStuff2(values1.slice(3));
});
Unless doStuff1 has side effects that you want to happen before the second set of promises resolve, if the first set resolves first? That would be weird and probably deserving of refactoring, but for that, just return the second promise from the handler of the first and chain them:
Promise.all([promise1, promise2, promise3]).then(function(values) {
doStuff1(values1);
return Promise.all([promise4, promise5, promise6]);
})
.then(function(values) {
doStuff2(values);
});
Sure!
// promiseGroup1
const stuff1Promise = new Promise(resolveStuff1 => {
Promise.all([promise1, promise2, promise3]).then(function(values) {
const stuff1 = doStuff1();
resolveStuff1(stuff1);
})
});
// promiseGroup2
Promise.all([promise4, promise5, promise6, stuff1Promise]).then(function(values) {
doStuff2()
})
This lets both your promise groups to kick off simultaneously, and also ensures that your doStuff2 is invoked only after your doStuff1 has finished.

Extend ES6 Promise to convert callback to Deferred pattern

I would like to know what do you think about this kind of extension for ES6 Promise (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise):
Promise.create = function() {
var deferred;
var promise = new Promise(function (resolve, reject) {
deferred = {
resolve: resolve,
reject: reject
};
});
promise.deferred = deferred;
return promise;
}
Like that it avoid using the first callback to get cleaner code:
var requestsdeferred = Promise.create();
obj.myFunctionWithCallback(function(){
obj.mySecondFunctionWithCallback(function(){
requestsdeferred.resolve('all done!');
});
});
requestsdeferred.then(function(result) {
});
instead of:
var p = new Promise(function(resolve, reject){
obj.myFunctionWithCallback(function(){
obj.mySecondFunctionWithCallback(function(){
resolve('all done!');
});
});
});
p.then(function(){
});
Which need a callback.
What do you think ?
Neither is the correct/regular usage of a promise. The usual way to use a promise would be:
ajax.get('/get').then(function(){
return ajax.get('/cart');
}).then(function(){
alert('all done!');
});
Promises chain, you can return a promise from a then handler and it will cause the returned promise from the then to wait for its completion and assume its state.
Of course, unless the promises depend you can (and likely should) execute them concurrently:
Promise.all([ajax.get("/get"), ajax.get("/cart")]).then(function(results){
// both done here, concurrently
});
Avoid the explicit construction anti-pattern, no need to create a deferred. The reason the API does not look the way you describe it is so that if you throw synchronously it will get converted to a rejection and you won't have to add both a .catch and a catch (e){ handler to your code which is error prone.
It's just an obfuscation of the ES6 standard, and I don't see much benefit to your addition. It's just a layer of abstraction that isn't really needed.
I'd suggest a different approach that plays nice with ES6 promises...
The following is correct, but irrelevant (see comments) :
Any "thenable" can be turned into a standard Promise with Promise.resolve, so if your ajax is (for instance) created with jQuery's $.ajax, you might:
var prom1 = Promise.resolve(ajax.get('/get'));
var prom2 = Promise.resolve(ajax.get('/cart'));
We can create these together (so the requests run concurrently), then wait for all of the promises to complete with Promise.all:
Promise.all([req1, req2])
.then(function(vals){
//and get the results in the callback
var getData = vals[0];
var cartData = vals[1];
});

angularjs check if 2 promises have returned

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.

Categories