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);
});
Related
I have a function that does a bunch of work then returns a resolved Promise. Is there a difference in the timing when each will be resolved?
Option 1
function returnPromise() {
// do a bunch of stuff
return Promise.resolve();
}
and this way:
Option 2
function returnPromise() {
return new Promise((resolve, reject) => {
//do a bunch of stuff
resolve();
});
}
Does Option 1 release control after all the work is done, and Option 2 release control as soon as the function is called? I feel like this has root in the fact I don't fully understand the event loop. Thanks in advance for helping me understand this.
Is there a difference in the timing when each will be resolved?
No difference. The Promise executor (the callback you pass to new Promise()) is called immediately and synchronously. So, in BOTH cases, you are immediately and synchronously returning an already resolved promise and all the code in your function has already executed.
There should be no meaningful difference in execution timing. Of course, one might take slightly different number of CPU cycles to execute, but both have the exact same outcome and both immediately return a promise that is already resolved so there should be no difference to the calling code at all.
Promise.resolve() is just meant as a more compact (and probably more efficient) means of creating an already resolved promise.
Does Option 1 release control after all the work is done, and Option 2 release control as soon as the function is called?
They both return when all your work is done and they return an already resolved promise. This is because the executor callback to new Promise() is called synchronously (before your function returns).
I feel like this has root in the fact I don't fully understand the event loop. Thanks in advance for helping me understand this.
In this particular circumstance, all your code is run synchronously so there is no particular involvement of the event loop. The returnPromise() function returns (in both cases) when your code in the function is done executing synchronously. There is no async code here.
The event loop gets involved when you do .then() on the returned promise because even though the promise (in both cases) is already resolved, the .then() handler gets queued in the event queue and does not run until the rest of your Javascript after your .then() handler is done executing.
console.log("1");
returnPromise().then(function() {
console.log("2");
});
console.log("3");
This will generate identical output results:
1
3
2
with both versions of your returnPromise() function because .then() handlers are queued until the next tick of the event loop (e.g. after the rest of your current Javascript thread of execution is done).
Is there a difference with doing it this way?
No, both your examples do the exact same thing.
Promise.resolve and Promise.reject are simply static methods on the Promise Class that help you avoid constructing a whole Promise when you don't really need to.
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
});
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.
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.
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.