Node JS Async Promise.All issues - javascript

I'm trying to execute an asynchronous routine for a bunch of items in a list that I get from a database, but I'm having trouble understanding how promise.all works and what it does.
Here is the code I'm using right now:
/**
* Queues up price updates
*/
function updatePrices() {
console.log("~~~ Now updating all listing prices from Amazon API ~~~");
//Grabs the listings from the database, this part works fine
fetchListings().then(function(listings) {
//Creates an array of promises from my listing helper class
Promise.all(listings.map(function(listing){
//The promise that resolves to a response from the routine
return(listing_helper.listingPriceUpdateRoutine(listing.asin));
})).then(function(results){
//We want to log the result of all the routine responses
results.map(function(result){
console.log(result);
});
//Let us know everything finished
console.log("~~~ Listings updated ~~~");
}).catch(function(err){
console.log("Catch: ", err);
});
});
}
Right now, the only thing I get in the log is
~~~ Now updating all listing prices from Amazon API ~~~
I've tried adding a logging piece into the routine that is called and the routines all run successfully and log what they should, but promise.all.then doesn't execute.
I've tried just doing:
Promise.all(bleh).then(console.log("We did it"));
and that worked, but when I put a function in the Then, nothing runs.
Please help!

Promise.all() itself is pretty simple. You pass it an array of promises. It returns a new promise that will resolve when all the promises in your array resolve or will reject when any individual promise in the array rejects.
var pAll = Promise.all([p1, p2, p3]);
pAll.then(function(r) {
// all promises resolved
// r is an array of results
}, function(err) {
// one or more promises rejected
// err is the reason for the first promise that rejected
});
Some reasons that Promise.all() might not work in your code:
You aren't passing an array of promises to it.
Some of the promises in the array you pass never resolve or reject thus Promise.all() never resolves/rejects its master promise
You aren't properly passing callbacks to .then() handlers where you should be
You aren't properly returning promises from internal functions so they propagate out or chain properly
Your example:
Promise.all(bleh).then(console.log("We did it"));
Is wrong. You must pass a function reference to .then() like this:
Promise.all(bleh).then(function() {
console.log("We did it")
});
In your case, the console.log() would execute immediately and not wait for the promises to be resolved.
In your detailed code are you 100% sure that:
listing_helper.listingPriceUpdateRoutine(listing.asin)
is returning a promise? And, that that promise will get resolved or rejected properly?
Note to Readers - If you read all the comments, you can see that the OP's actual issue was not with Promise.all(), but they were getting rate limited for sending requests too quickly to the target host. Since that should have been propagating a request error back which should have been easily visible, the OP apparently also has a problem with error handling or propagation which is likely in code that was not disclosed here.

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.

how can I get the result for the [ Promise { <pending> } ]? [duplicate]

This is more of a conceptual question. I understand the Promise design pattern, but couldn't find a reliable source to answer my question about promise.all():
What is(are) the correct scenario(s) to use promise.all()
OR
Are there any best practices to use promise.all()? Should it be ideally used only if all of the promise objects are of the same or similar types?
The only one I could think of is:
Use promise.all() if you want to resolve the promise only if all of the promise objects resolve and reject if even one rejects.
I'm not sure anyone has really given the most general purpose explanation for when to use Promise.all() (and when not to use it):
What is(are) the correct scenario(s) to use promise.all()
Promise.all() is useful anytime you have more than one promise and your code wants to know when all the operations that those promises represent have finished successfully. It does not matter what the individual async operations are. If they are async, are represented by promises and your code wants to know when they have all completed successfully, then Promise.all() is built to do exactly that.
For example, suppose you need to gather information from three separate remote API calls and when you have the results from all three API calls, you then need to run some further code using all three results. That situation would be perfect for Promise.all(). You could so something like this:
Promise.all([apiRequest(...), apiRequest(...), apiRequest(...)]).then(function(results) {
// API results in the results array here
// processing can continue using the results of all three API requests
}, function(err) {
// an error occurred, process the error here
});
Promise.all() is probably most commonly used with similar types of requests (as in the above example), but there is no reason that it needs to be. If you had a different case where you needed to make a remote API request, read a local file and read a local temperature probe and then when you had data from all three async operations, you wanted to then do some processing with the data from all three, you would again use Promise.all():
Promise.all([apiRequest(...), fs.promises.readFile(...), readTemperature(...)]).then(function(results) {
// all results in the results array here
// processing can continue using the results of all three async operations
}, function(err) {
// an error occurred, process the error here
});
On the flip side, if you don't need to coordinate among them and can just handle each async operation individually, then you don't need Promise.all(). You can just fire each of your separate async operations with their own .then() handlers and no coordination between them is needed.
In addition Promise.all() has what is called a "fast fail" implementation. It returns a master promise that will reject as soon as the first promise you passed it rejects or it will resolve when all the promises have resolved. So, to use Promise.all() that type of implementation needs to work for your situation. There are other situations where you want to run multiple async operations and you need all the results, even if some of them failed. Promise.all() will not do that for you directly. Instead, you would likely use something like Promise.settle() for that situation. You can see an implementation of .settle() here which gives you access to all the results, even if some failed. This is particularly useful when you expect that some operations might fail and you have a useful task to pursue with the results from whatever operations succeeded or you want to examine the failure reasons for all the operations that failed to make decisions based on that.
Are there any best practices to use promise.all()? Should it be
ideally used only if all of the promise objects are of the same or
similar types?
As explained above, it does not matter what the individual async operations are or if they are the same type. It only matters whether your code needs to coordinate them and know when they all succeed.
It's also useful to list some situations when you would not use Promise.all():
When you only have one async operation. With only one operation, you can just use a .then() handler on the one promise and there is no reason for Promise.all().
When you don't need to coordinate among multiple async operations.
When a fast fail implementation is not appropriate. If you need all results, even if some fail, then Promise.all() will not do that by itself. You will probably want something like Promise.allSettled() instead.
If your async operations do not all return promises, Promise.all() cannot track an async operation that is not managed through a promise.
Promise.all is for waiting for several Promises to resolve in parallel (at the same time). It returns a Promise that resolves when all of the input Promises have resolved:
// p1, p2, p3 are Promises
Promise.all([p1, p2, p3])
.then(([p1Result, p2Result, p3Result]) => {
// This function is called when p1, p2 and p3 have all resolved.
// The arguments are the resolved values.
})
If any of the input Promises is rejected, the Promise returned by Promise.all is also rejected.
A common scenario is waiting for several API requests to finish so you can combine their results:
const contentPromise = requestUser();
const commentsPromise = requestComments();
const combinedContent = Promise.all([contentPromise, commentsPromise])
.then(([content, comments]) => {
// content and comments have both finished loading.
})
You can use Promise.all with Promise instance.
It's hard to answer these questions as they are the type that tend to answer themselves as one uses the available APIs of a language feature. Basically, it's fine to use Promises any way that suits your use case, so long as you avoid their anti-patterns.
What is(are) the correct scenario(s) to use promise.all()
Any situation in which an operation depends on the successful resolution of multiple promises.
Are there any best practices to use promise.all()? Should it be ideally used only if all of the promise objects are of the same or similar types?
Generally, no and no.
I use promise.all() when I have to do some requests to my API and I don't want to display something before the application loads all the data requested, so I delay the execution flow until I have all the data I need.
Example:
What I want to do I want to load the users of my app and their products (imagine that you have to do multiple requests) before displaying a table in my app with the user emails and the product names of each user.
What I do next I send the requests to my API creating the promises and using promise.all()
What I do when all the data has been loaded Once the data arrives to my app, I can execute the callback of promises.all() and then make visible the table with the users.
I hope it helps you to see in which scenario makes sense to use promises.all()
As #joews mentioned, probably one of the important features of Promise.all that should be explicitly indicated is that it makes your async code much faster.
This makes it ideal in any code that contains independent calls (that we want to return/finish before the rest of the code continues), but especially when we make frontend calls and want the user's experience to be as smooth as possible.
async function waitSecond() {
return new Promise((res, rej) => {
setTimeout(res, 1000);
});
}
function runSeries() {
console.time('series');
waitSecond().then(() => {
waitSecond().then(() => {
waitSecond().then(() => {
console.timeEnd('series');
});
});
});
}
function runParallel() {
console.time('parallel');
Promise.all([
waitSecond(),
waitSecond(),
waitSecond(),
]).then(() => {
console.timeEnd('parallel');
});
}
runSeries();
runParallel();
I tend to use promise all for something like this:
myService.getUsers()
.then(users => {
this.users = users;
var profileRequests = users.map(user => {
return myService.getProfile(user.Id); // returns a promise
});
return Promise.all(profileRequests);
})
.then(userProfilesRequest => {
// do something here with all the user profiles, like assign them back to the users.
this.users.forEach((user, index) => {
user.profile = userProfilesRequest[index];
});
});
Here, for each user we're going off and getting their profile. I don't want my promise chain to get out of hand now that i have x amount of promises to resolve.
So Promise.all() will basically aggregate all my promises back into one, and I can manage that through the next then. I can keep doing this for as long as a like, say for each profile I want to get related settings etc. etc. Each time I create tonnes more promises, I can aggregate them all back into one.
Promise.all-This method is useful for when you want to wait for more than one promise to complete or The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first passed promise that rejects.
2.Just use Promise.all(files).catch(err => { })
This throws an error if ANY of the promises are rejected.
3.Use .reflect on the promises before .all if you want to wait for all
promises to reject or fulfill
Syntax -Promise.all(iterable);
Promise.all passes an array of values from all the promises in the iterable object that it was passed.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
var isCallFailed = false;
function myEndpoint1() {
return isCallFailed ? Promise.reject("Bohoo!") :Promise.resolve({"a":"a"});
}
function myEndpoint2() {
return Promise.resolve({"b":"b"});
}
Promise.all([myEndpoint1(), myEndpoint2()])
.then(values => {
var data1 = values[0];
var data2 = values[1];
alert("SUCCESS... data1: " + JSON.stringify(data1) + "; data2: " + JSON.stringify(data2));
})
.catch(error => {
alert("ERROR... " + error);
});
you can try another case by making isCallFailed = true.
Use Promise.all only when you need to run a code according to the result of more than one asynchronous operations using promises.
For example:
You have a scenario like, You need to download 2000 mb file from server, and at the same time you are going to free the user storage to make sure it can save the downloaded file.
And you need to save only in case if the file is downloaded successfully and the storage space is created successfully.
you will do like this.
your first asynchronous operation
var p1 = new Promise(function(resolve, reject) {
// you need to download 2000mb file and return resolve if
// you successfully downloaded the file
})
and your second asynchronous operation
var p2 = new Promise(function(resolve, reject) {
// you need to clear the user storage for 2000 mb
// which can take some time
})
Now you want to save only when both of the promises resolved successfully, otherwise not.
You will use promise.all like this.
Promise.all([p1,p2]).then((result)=>{
// you will be here only if your both p1 and p2 are resolved successfully.
// you code to save the downloaded file here
})
.catch((error)=>{
// you will be here if at-least one promise in p1,p2 is rejected.
// show error to user
// take some other action
})
Promise.all can be used in a scenario when there is a routine which is validating multiplerules based on particular criteria and you have to execute them all in parallel and need to see the results of those rules at one point. Promise.all returns the results as an array which were resolved in your rule vaidator routine.
E.g.
const results = await Promise.all([validateRule1, validateRule2, validateRule3, ...]);
then results array may look like (depending upon the conditions) as for example: [true, false, false]
Now you can reject/accept the results you have based on return values. Using this way you won't have to apply multiple conditions with if-then-else.
If you are interested only Promise.all then read below Promise.all
Promise (usually they are called "Promise") - provide a convenient way to organize asynchronous code.
Promise - is a special object that contains your state. Initially, pending ( «waiting"), and then - one of: fulfilled ( «was successful") or rejected ( «done with error").
On the promise to hang callbacks can be of two types:
unFulfilled - triggered when the promise in a state of "completed
successfully."
Rejected - triggered when the promise in the "made in error."
The syntax for creating the Promise:
var promise = new Promise(function(resolve, reject) {
// This function will be called automatically
// It is possible to make any asynchronous operations,
// And when they will end - you need to call one of:
// resolve(result) on success
// reject(error) on error
})
Universal method for hanging handlers:
promise.then(onFulfilled, onRejected)
onFulfilled - a function that will be called with the result with
resolve.
onRejected - a function that will be called when an error reject.
With its help you can assign both the handler once, and only one:
// onFulfilled It works on success
promise.then(onFulfilled)
// onRejected It works on error
promise.then(null, onRejected)
Synchronous throw - the same that reject
'use strict';
let p = new Promise((resolve, reject) => {
// то же что reject(new Error("o_O"))
throw new Error("o_O");
});
p.catch(alert); // Error: o_O
Promisification
Promisification - When taking asynchronous functionality and make it a wrapper for returning PROMIS.
After Promisification functional use often becomes much more convenient.
As an example, make a wrapper for using XMLHttpRequest requests
httpGet function (url) will return PROMIS, which upon successful data loading with the url will go into fulfilled with these data, and in case of error - in rejected with an error information:
function httpGet(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function() {
if (this.status == 200) {
resolve(this.response);
} else {
var error = new Error(this.statusText);
error.code = this.status;
reject(error);
}
};
xhr.onerror = function() {
reject(new Error("Network Error"));
};
xhr.send();
});
}
As you can see, inside the function XMLHttpRequest object is created and sent as usual, when onload / onerror are called, respectively, resolve (at the status 200) or reject.
Using:
httpGet("/article/promise/user.json")
.then(
response => alert(`Fulfilled: ${response}`),
error => alert(`Rejected: ${error}`)
);
Parallel execution
What if we want to implement multiple asynchronous processes simultaneously and to process their results?
The Promise class has the following static methods.
Promise.all(iterable)
Call Promise.all (iterable) receives an array (or other iterable object) and returns PROMIS PROMIS, which waits until all transferred PROMIS completed, and changes to the state "done" with an array of results.
For example:
Promise.all([
httpGet('/article/promise/user.json'),
httpGet('/article/promise/guest.json')
]).then(results => {
alert(results);
});
Let's say we have an array of URL.
let urls = [
'/article/promise/user.json',
'/article/promise/guest.json'
];
To download them in parallel, you need to:
Create for each URL corresponding to PROMIS.
Wrap an array of PROMIS in Promise.all.
We obtain this:
'use strict';
let urls = [
'/article/promise/user.json',
'/article/promise/guest.json'
];
Promise.all( urls.map(httpGet) )
.then(results => {
alert(results);
});
Note that if any of Promise ended with an error, the result will
Promise.all this error.
At the same time the rest of PROMIS ignored.
For example:
Promise.all([
httpGet('/article/promise/user.json'),
httpGet('/article/promise/guest.json'),
httpGet('/article/promise/no-such-page.json') // (нет такой страницы)
]).then(
result => alert("не сработает"),
error => alert("Ошибка: " + error.message) // Ошибка: Not Found
)
In total:
Promise - is a special object that stores its state, the current
result (if any), and callbacks.
When you create a new Promise ((resolve, reject) => ...) function
argument starts automatically, which should call resolve (result) on
success, and reject (error) - error.
Argument resolve / reject (only the first, and the rest are ignored)
is passed to handlers on this Promise.
Handlers are appointed by calling .then / catch.
To transfer the results from one processor to another using Channing.
https://www.promisejs.org/patterns/

Angular q.all instant vs delayed responses

I have a methodology question. Currently I am using $q.all to capture multiple promises in a single return, then processing all the results as single request.
ie: $q.all([promise1(),promise2(),promise3(),promise(4),promise5()])..then(function(response){ ...}
However, I am noticing that sometimes different promises are being returned at significantly different time frames. All the promises are http calls to third party sites. When any particular promise is delayed by say 8 seconds...or 14 seconds, then the final results of all promises are delayed by that same duration. The weakest...rather 'slowest'...link syndrome.
What is another method that I can use to call all the promises at the same time yet still allow for results to be processed, and viewed by the user, as they come in? To NOT wait on all of them to be returned before processing them all at once?
As suggested in the comments you could just use them separately, but if you really want to call them all at the same time and handle them in one promise, you can use the notify-callback of the promise. I've created an extension to $q that uses this notify() function to resolve the promises as one:
app.run(function($q){
$q.each = function(promises){
var deferred = $q.defer();
promises.forEach(function(promise){
promise.then(function(data){
deferred.notify(data);
});
});
return deferred.promise;
};
});
This is a pretty naive implementation that doesn't handle errors for instance, but it gives you an idea of what's involved.
Then you'd just use it like this:
var promises = [promise1(),promise2(),promise3(),promise(4),promise5()];
$q.each(promises).then(null, null, function(data){
console.log(data); // This is called when each promise resolves.
});
Here's a Plunker showing this in action
Keep in mind that the methods like then() or $q.all() do not determine how the promises execute; they merely establish the semantics for when you want to respond. What I mean is, the promises start running when you create them even though a fluent reading of myPromise.then(doSomething) might seem to imply otherwise.
Combine that with the fact that $q.all doesn't so much "combine promises" as it creates a new promise that resolves or rejects based on the resolution or rejection status of the original promises; and that a promise is not limited to only a single handler...
promise1.then(function () {
//stuff that only cares about promise1 and needn't wait for the others
});
$q.all(promise1, promise2, ...).then(function () {
//stuff that can't be done until everything finishes
});

What to use instead of Promise.all() when you want all results regardless of any rejections

I'm using the Bluebird promise library in a node.js project. I have two operations that both return promises and I want to know when both are done, whether resolved or rejected and I need the return values from both. I'm reading the contents of multiple files and some of the files may not exist and that's an OK condition, so though fs.readFileAsync() will fail if the file doesn't exist, I still need the results of the other read operation.
Promise.all(p1, p2) will reject if either p1 or p2 rejects and I don't think I'll necessarily get the data from the other one.
Of all the other Bluebird operations (.some(), .any(), .settle(), etc...) which is most appropriate to this situation? And, how is the data passed back such that you can tell which ones succeeded and which ones didn't?
That would be indeed be .settle. Settle takes an array of promises and returns PromiseInspection instances for all of them when they resolve. You can then check if they're fulfilled or rejected and extract their value.
For example:
Promise.settle(['a.txt', 'b.txt'].map(fs.readFileAsync)).then(function(results){
// results is a PromiseInspetion array
console.log(results[0].isFulfilled()); // returns true if was successful
console.log(results[0].value()); // the promise's return value
});
Your use case is pretty much what Promise.settle exists for.
Only by trying different options and then ultimately stepping through code in the debugger, I figured out how to do this using .settle():
// display log files
app.get('/logs', function(req, res) {
var p1 = fs.readFileAsync("/home/pi/logs/fan-control.log");
var p2 = fs.readFileAsync("/home/pi/logs/fan-control.err");
Promise.settle([p1, p2]).spread(function(logFile, errFile) {
var templateData = {logData: "", errData: ""};
if (logFile.isFulfilled()) {
templateData.logData = logFile.value();
}
if (errFile.isFulfilled()) {
templateData.errData = errFile.value();
}
res.render('logs', templateData);
}).catch(function(e) {
console.log("err getting log files");
// figure out what to display here
res.render(e);
});
});
If anyone from the Bluebird team comes along, the doc for how to use .settle() is missing about 2/3 of what is needed to understand how to use it. It makes reference to a PromiseInspection, but makes no reference on how to use that. A simple code example in the doc for .settle() and for how you examine the results that .settle() returns would have saved hours of time.

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);
});

Categories