I'm trying to understand what Promise.all() is doing exactly.
As far as I understand,
promise is something which holds a return value for asynchronous execution in javascript.
So the values encapsulated(?) by promise is not directly accessible in sychronoous running.
(Terminology warning! I'm going to use analogy to show how I see promise and promise.all())
To get a direct access to the promisified values,
I need to peel off a shell called promise, which is
promise.all at the end of asynchronous function.
after this 'peeling-off', I could access to a synchronously available values.
Am I understanding Promise.all correctly?
Thank you so much.
Example is from mdn website.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
all the promises and just synchronous value (const promise2) were successfully approached by synchronous execution 'console.log()'.
If I don't peel off the promise shell like below,
Promise.all([promise2, promise3]).then((values) => {
console.log(values);
console.log(promise1)
});
The values that js spits out are as below.
Array [42, "foo"]
[object Promise]
Please feel free to criticize my analogy and
let me know if I understand something wrong.
Thank you in advance.
Your analogy is a very interesting one, but I'm sure it's a common perception of how Promises work. Promises are constructs that manage deffered values - values that will be at some stage, time-dependent. Using the term "wrapping" makes it sound like the value is already there, when in fact it most likely isn't.. yet.
A promise can be used to represent the response from an API, or perhaps a lookup from a database - both of these take time - something synchronous code can't handle. You might make a request, and get a promise in response. You can then use this promise as a helper to get the value you intended to receive.
When you call promise.then(value => ...), the then function is waiting until the value is ready. Inside the promise, something must call resolve(value) before the then function will fire (note that the promise can also be rejected via reject, in which case promise.catch would be fired). Here's a full example:
const promise = new Promise(resolve => {
setTimeout(() => {
resolve(10);
}, 2000);
});
promise.then(value => {
// This fires after about 2 seconds
console.log(value); // 10
});
So the trick here is to visualise that getting results from a promise occurs on a different "thread".. perhaps in a callback or after an await call. Also, once a promise has been resolved, calling then a second time will return the same value as previously, and it will be faster, but still not instant as promises "values" are always asynchronously returned.
Promise.all waits until all the provided promises have resolved. What is returned by Promise.all is an array containing all of the resolved results in order. So if you have the following:
const promise1 = Promise.resolve(12); // Asynchronously returns 12
const promise2 = new Promise(resolve => {
setTimeout(() => {
resolve(10);
}, 2000);
});
Promise.all([promise1, promise2]).then(results => {
// results will be [12, 10], and will fire after about 2 seconds
});
// here, even though we're after the promise assignments,
// the values to BOTH of the promises are still not yet defined (not resolved)
TLDR; A promise is a class that records a value once its provided function resolves. The then method will call its callback with the value once it is set by the promise function (by calling resolve or reject).
Related
This is the code I'm going to be talking about.
view: async (req, res, next) => {
let formato = req.query.formato || 'details';
try {
let mode = Client.getMode(formato);
let options = {
columns: mode.columns,
withRelated: mode.withRelated,
};
let client_promises = [ ]
req.query['ids'].map( id => {
let client = Client.findById(id, options);
client_promises.push(client)
})
let response = await Promise.all(cliente_promesas)
return res.json({ success: true, data: response });
} catch (error) {
return next(error);
}
},
I understand that the .map function iterates over an array of ids, which then is passed to Client.findById so it can return a promise to be fulfilled, getting the client's data when it resolves.
Now, those promises are pushed to an array, which then is passed to Promise.all, but I dont really understand where they are being resolved. Isnt Promise.all just passing a resolved promise when all promises in the array are resolved?
I also understand that await just makes the code wait for the resolution of the promise before continuing.
But where are the promises in client_promises being resolved?
I know this is basic but for the life of me I cant seem to read enough manuals and guides to be able to understand this.
All Promise.all does is wait for every Promise in the array passed to it to be done. It doesn't "fire" them. In fact every Promise in the array passed might even be in a resolved state. The Promises are "hot" from the moment they are created.
For your example, the function to get an item by id starts immediately and synchronously returns a Promise that will eventually resolve to whatever object is retrieved by id. This is key: the returning of the Promise is not the asynchronous part, it's the resolution.
Promise.all makes all the promises one big promise.
Consider the example below. I take 3 ids and do exactly what you do, I call findById and put what is returned by the function (a Promise) into an array, promises. In the findById, I also add an extra .then call to demonstrate how these Promises are "hot" and not waiting to be called by Promise.all. Also note that I still return the p.
By the time we actually get to the Promise.all, all of the Promises in promises have actually resolved, that's why you see them print to console first. They all take 100-600 milliseconds to resolve, but we actively wait a full 1000 milliseconds before we call Promise.all.
Unfortunately (kind of) there is no API to reveal the state of a Promise using the native implementation. I think there used to be ways with user land libraries like Bluebird and jQuery, but not with how the browser does it. Otherwise, we could inspect the Promise right before calling the Promise.all and see whether they were resolved or pending.
/**
* Utility function to wait a duration before resolving
* #param {number} [delay=100] How long to wait
* #returns {Promise<undfined>} Promise that will resolve after delay
*/
function timeout(delay = 100) {
return new Promise(resolve => {
setTimeout(resolve, delay);
});
}
/**
* Simulated find function that returns an object
* #param {number} id The id of the object to get
* #returns {Promise<object>} The fake DB object
*/
async function findById(id) {
await timeout((Math.random() * 500) + 100);
return {
id,
data: `foo-${id}`
};
}
(async function() {
const idsToGet = [1, 2, 3];
const promises = idsToGet.map(id => {
// Call to get the object
const p = findById(id);
// Let's add another listener here to know when they are done
p.then(r => {
console.log(`${r.id} is done`);
});
// Still return the actual Promise created by findById
return p;
});
// Just for kicks
await timeout(1000);
// Wait for EVERYTHING to be done
const res = await Promise.all(promises);
console.log(JSON.stringify(res, null, 4));
}());
Promise.all() takes list/ array of unresolved promises.
It is kind of like a big one promise that takes all the unresolved promises and until all of them are resolved the Promise.all() is unresolved.
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
In the above example, you can see that we are passing 3 promises to Promise.all()
and when all of them are fulfilled then only .then will be triggered.
in your case:
Client.findById(id, options);
must be returning a promise object which you are pushing into client_promises array.
and then feeding them to Promise.all(), until this point, your promises are just promises they are not resolved.
promise.all also returns a promise and as you have put await in front of it.
it will wait until of them re resolved and give you an array of resolved promises.
The promises are actually "fired" (that is, the code starts to run) when you do let client = Client.findById(id, options);. await Promise.all then waits until all of them are resolved or one of them is rejected in which case Promise.all also rejects with the value of the first promise rejection.
I'd like to have a promise to a promise, something like this:
let first = new Promise(resolveFirst => {
setTimeout(() => {
resolveFirst("resolved!");
}, 2000)
});
let second = new Promise(resolveSecond => {
setTimeout(() => {
resolveSecond(first);
}, 10)
});
second.then(secondValue => {
console.log("second value: ", secondValue);
secondValue.then(firstValue => {
console.log("first value: ", firstValue);
});
});
So that the console.log("second value: ", secondValue); is printed after 10 millies and then the console.log("first value: ", firstValue) will be printed 2000 afterwards.
What happens though is that I get:
second value: resolved!
And an error:
Uncaught (in promise) TypeError: secondValue.then is not a function
Together after 2010 millies.
It seems that when the second promise is resolved, and the first one is returned then it automatically waits for this first promise to resolve as well.
Why is that? And how do I break between them?
Edit
Here's a solution that was posted on facebook using Array.reduce():
const runPromisesInSeries =
ps => ps.reduce((p, next) =>
p.then(next), Promise.resolve());
const delay = d => new Promise(r => setTimeout(r, d));
runPromisesInSeries([() => delay(1000), () => delay(2000)]);
//executes each promise sequentially, taking a total of 3 seconds to complete
(https://www.facebook.com/addyosmaniofficial/photos/a.10151435123819601.1073741825.129712729600/10155386805609601/?type=3&theater)
By design, a promise that is resolved with a second promise takes on the value and state of the 2nd promise after the 2nd promise becomes settled (fulfilled or rejected), waiting for it to be settled as necessary.
It is not possible to fulfill a promise with a promise or thenable object (any object with a then method`) value unless the promise library is seriously flawed (older versions of JQuery would fulfill their own promise objects with a promise object from a different library).
Promise rejection does not have the same checks in place and will happily pass a promise object down the chain without waiting for it to be resolved. So you could reject the 2nd promise with the first and pick it up in a catch clause.
Although technically feasible I strongly advise against doing so except to prove it can be done - it's a maintenance issue for a third party trying to understand the code.
While you could pass the promise as an object property down the success channel of a promise chain, re-analysis of promise composition may provide a better or more standard solution. E.G. Promise.all waits for for two or more independent promises to be fulfilled before proceeding on a common task.
That's just part of their charm: If your promise A resolves to a thenable B, then A resolves only after B resolves, and A takes B's resolved value. That's part of both Promises/A+ and ES6, as part of the "promise resolution procedure".
You can see some of the advantages of that if (say) one action requires an action before its completion (like login), or requires loading another page of results, or has retry logic of its own.
Though it's not very idiomatic, if you want to return an unresolved promise immediately without waiting for it, you can do so by passing it in an {object} or [array], but there might not be much reason for that: Other than waiting for its completion, what would you do with a returned promise?
You can chain then only to a promise.
secondValue is not a promise, it's just the value that returned when you called the second promise. or the resolved value from that promise.
If you want that to work, try this:
let first = new Promise(resolveFirst => {
setTimeout(() => {
resolveFirst("resolved!");
}, 2000)
});
let second = new Promise(resolveSecond => {
setTimeout(() => {
resolveSecond(first);
}, 10)
});
second.then(secondValue => {
console.log("second value: ", secondValue);
/** first is a Promise. return a promise, and the next "then"
* will pass the result of that Promise.
*/
return first
})
.then(firstValue => {
console.log(firstValue)
})
EDIT 1
Further explanation for why second promise resolved the eventual value (string) of the first promise, and not the promise itself, can be found on mdn:
Promise.resolve()
if the value was a promise, that object becomes the result of the call to Promise.resolve; otherwise the returned promise will be fulfilled with the value.
I am working on building Promise chain with setTimeouts in them. All of the Promises needs to be run in series not parallel. I am using Bluebird module to achieve serial flow of Promise execution.
Can someone please explain me why this code gives me output of 1,2,3,4 instead of 4,3,2,1?
var bluebirdPromise = require('bluebird');
function p1(value) {
return new Promise(function(resolve, reject) {
setTimeout(function(resolve) {
console.log(value);
resolve;
}, value * 1000);
});
}
var arr = [p1(4), p1(3), p1(2), p1(1)];
bluebirdPromise.reduce(arr,
function(item, index, length) {
}).then(function (result) {
});
There are several issues:
The console.log you have is not made dependent on a previous resolved promise. There is just the time-out that determines when the output will happen. As you create all four promises at the "same" time, and thus all four setTimeout calls are invoked simultaneously, their callbacks will be called at the determined time-out. It does not matter how you chain promises afterwards... To solve this, you need to move the console.log in a then callback, because that callback will only be executed when the previous promise in the chain has been resolved.
The resolve function is not called in your code. You need to add parentheses.
The resolve parameter of the setTimeout callback hides the real function with the same name: you need to remove that parameter.
Here is the suggested correction. For this snippet I have replaced the bluebird reduce with a standard Array#reduce, but it would work similarly with bluebird's reduce:
function p1(value) {
return new Promise(function(resolve, reject) {
setTimeout(function() { // ***
resolve(value); // ***
}, value * 1000);
});
}
var arr = [p1(4), p1(3), p1(2), p1(1)];
arr.reduce(function(promise, next) {
return promise.then(_ => next).then( value => {
console.log(value); // ***
return value;
});
}, Promise.resolve());
If you have a promise-creator function, p, and you want to run a sequence of promises in serial, there's no need for you to load an array with promises – instead, just let it be a normal array of values
Notice I'm not using value * 1000 here either – in your code, you thought you had to artificially choreograph the promises to fire in a particular order using calculated setTimeout delays; that's just not the case. Carefully observe the evaluation of the code below to see how we have a 1-second delay between each promise and .then keeps things in order
Also note that this code will start outputting immediately after the first promise resolves – as opposed to waiting for all promises to resolve before outputting all values
const p = x =>
new Promise(f =>
setTimeout(f, 1e3, x))
const arr = [4,3,2,1]
arr.reduce((acc, x) =>
acc.then(() => p(x)).then(console.log), Promise.resolve())
OK, so you have these promises running in serial order, but why? Unless later steps somehow depend on the result of earlier steps, there's no reason why you'd want to slow these down – ie, each promise's result is not dependent on the others, so just calculate them all as fast as possible. But you're worried that the order will be lost, right? Don't worry, everything will be OK – I'll even use a random delay to show you that the time each promise takes matters not
const p = x =>
new Promise(f =>
setTimeout(f, 1e3 * Math.random(), x))
const arr = [4,3,2,1]
arr.map(p).reduce((acc, x) =>
acc.then(() => x).then(console.log), Promise.resolve())
So now, all of the promises can start immediately, and output will start as soon as the first promise is resolved (unlike Promise.all which would wait for all promises to finish before any values are available to you).
I only mention this as an alternative because the example you provided shows no real need for the promises to be executed in serial. You may have naively simplified your problem's domain, but only you know whether that's the case.
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/
I have a question about attaching callback functions to promises in AngularJS.
Suppose I have a service with a function that returns a promise. I make a call to this function and store the promise locally. Then I define a callback function on the promise.
var promise = TestService.get();
console.log('We have a promise!');
promise.then(function (result){
console.log('Here is the result:'+result);
});
In this case, we have a potentially risky situation. If the promise is resolved before we get to promise.then(..., the result is not outputted to the console (until the next digest cycle).
Alternatively, I could write the above code like this:
TestService.get().then(function (result){
console.log('Here is the result:'+result);
});
My question:
Has the risk been mitigated in the second example? And if not, how can I make sure that the promise does not resolve before I have attached a callback?
A slightly more elaborate answer than yes/no would be much appreciated :)
The behavior you are describing does not occur, that can be seen through a simple example. Here we have a simple promise factory which returns a promise which resolves immediately.
'use strict';
var make = function() {
return new Promise(function(resolve, reject) {
resolve(2);
});
};
Then we create a new promise and assign it to a variable
var prom = make();
We can call .then on it as many times as we want. This is because promises are immutable, we don't change the original value by chaining methods on it.
prom.then(a => console.log(a));
// 2
prom.then(a => console.log(a));
// 2
Suppose I have a service with a function that returns a promise. I make a call to this function and store the promise locally. Then I define a callback function on the promise.
No, you are not attaching a callback. When you call the then method you are doing something called promise chaining. Each call to then returns a new promise object that will resolve to the value returned by the previous promise.
For example;
var promise1 = TestService.get();
var promise2 = promise1.then(function(value) {
console.log('service resolved: '+value);
return "Hello World";
});
var promise3 = promise2.then(function(value) {
console.log(value);
});
promise3.then(function(value) {
console.log(value);
});
The above example will output the following.
**some value from TestService**
Hello World
undefined
We don't know who originally resolve the value for the first promise. All we know is that the service returned a promise. From that moment on we can chain the promises by adding more calls to then.
In this case, we have a potentially risky situation. If the promise is resolved before we get to promise.then(..., the result is not outputted to the console (until the next digest cycle).
No, it does not matter when or what digest the promise is resolved. A promise can have it's then method called multiple times even after being resolved. It will continue to resolve to the value as long as it has not been rejected. The decision to resolve or reject a promise is outside the scope of the success or failure callbacks.
You can create a promise, resolve it to a value, wait several digests and add a handler to then and it will still work as expected.
Has the risk been mitigated in the second example? And if not, how can I make sure that the promise does not resolve before I have attached a callback?
Think of promises as containers. They are going to hold the value you expect, and you have to call then to get it. If for what ever reason the value is unavailable you can find out why by using the error callback. The when aspect of promises is purely an asynchronize issue, and the idea is for promises to hide those issues.
JavaScript is not multithreaded, your asynchronous AJAX call isn't actually made by the browser until your code returns.
var promise = TestService.get();
for (var i= 0;i<100000;i++){
console.log(i)
}
console.log('We have a promise!');
promise.then(function (result){
console.log('Here is the result:'+result);
});
Watch this with the network analyzer.