Difference between returning a value and returning Promise.resolve() from a function
I have problem in understanding that what happens when we simply return a value or when we return
Promise.resolve()
from a function.
So there are (at least) two different scenarios:
In just any old function
If it's just any old function (not a then
or catch
callback), then the difference is that return value;
directly returns the value, whereas return Promise.resolve(value);
returns a promise fulfilled with that value. It changes how the calling code uses the result. In the return value;
case, the calling code just directly uses it. In the return Promise.resolve(value);
case, the calling code needs to consume the promise, just like any other promise (and can't assume that the promise is already settled, even though it is).
If the function is meant to be the start of a promise chain, you'd use return Promise.resolve(value);
. (There are use cases for this; for instance, if the function may or may not need to start an asynchronous process: In the branch that doesn't have to, you'd still return a promise because the branch that has to do something asynchronous has to return a promise.) If it isn't, you'd just use return value;
.
In then
or catch
callback
I am trying to understand how promises chaining works.
In that case, you're talking about return value;
vs. return Promise.resolve(value);
in a then
or catch
callback. That's easy: There's no point at all to return Promise.resolve(value);
in a then
or catch
callback, it's redundant and unnecessary overhead; just use return value;
.
then
and catch
always return promises. If your callback returns a simple value (return value;
), the promise is fulfilled with that value. If your callback returns a thenable (loosely, a promise; e.g., return Promise.resolve(value);
), then the promise returned by then
/catch
is resolved to that thenable: When the thenable is settled, the promise is settled the same way. (And if your then
or catch
callback throws an error, the promise is rejected with that error.)
There are valid reasons to return a promise from a then
or catch
callback, if you're starting a new asynchronous process in that callback; but if you have an immediate value ready, there's no point in wrapping it in a promise — then
and catch
already do that.
Promise.resolve vs Promise.resolve().then()
The difference is in job to be done. While all of this methods are valid, they have different cost and predictability.
Promise.resolve()
produces single resolved Promise instance, and depending on value provided to the call JS engine have information to optimize it. It makes all work to be done in a single call to underlying code of the JS engine (usually C++, but could be Java or WASM). So it's always the best choice.Promise.resolve().then(() => API(/*...*/))
Produce several Promise instances: one atPromise.resolve()
and other at.then()
call. It also allocates more memory and make several (3 or more) redundant jumps between JS and the engine. It's hardly optimizable and requires intensive heuristics to be performed to figure out is this call optimizable. It's the worst option.new Promise((resolve) => resolve(API(/* ... */))
allocates one function and one Promise instance and makes two jumps between JS and the engine. It's harder to optimize this call, due to nature of JS.
What is the difference between returning a Promise with .then() and without .then()?
When you're using then
you're determining where you would like to handle the data (or error) resolved by the promise. If you chain it with then
immediately, then I guess it's fine for you to immediately address it.
But you might want to just get the promise itself, and take care of the result someplace else. Maybe you have a service file, whose sole purpose is to create HTTP requests, but you want to handle the data under a different scope - the scope of the calling function:
// service.js
callServer() {
return new Promise(...)
}
// file.js
callServer().then( /* there's a different scope here */ )
Maybe you even want to get several promises and then use Promise.all(promisesArray)
and only act once all promises have been resolved:
const movies = getMovies(); // promise
const actors = getActors(); // promise
const directors = getDirectors(); // promise
Promise([movies, actors, directors]).then(_ => /* handle data */ );
There could be many reasons depending on the application.
Difference between Promise returns
Both examples are pointless because code is synchronous.
If you have a traditional callback function such as setTimeout
you have to use new Promise
to convert it to a promise (you cannot return Promise.resolve(value)
from a callback:
const later = (howLong, value) =>
new Promise(
resolve =>
setTimeout(() => {
console.log(value);
resolve(value)
}, howLong)
);
Using Promise.resolve
can be used as an initial value for example when you reduce values asynchronously:
[1,2,3].reduce(
(all, item) =>
all.then(
() => later(2000, item)
),
Promise.resolve()//initial value of all
)
Another common use case is if your function has to return a promise but can return a value immediately. Let's say you fetch some data and cache it when you got it. The next time you call the function you want it to return a promise because the caller is expecting a promise. You wrap the cached value in a promise:
const getData = (
cache => () =>
(cache)
? Promise.resolve(cache)
: fetch("someURL").then(r=>r.json()).then(result=>{
cache=result;
return result;
})
)(false)
Difference between Promise.resolve() and just resolve()?
Promise.resolve
wraps an expression in a Promise. So Promise.resolve("File found");
is 'File found'
wrapped in a Promise that resolves immediately.
Look at where the wrapped Promise is going in this code - you're returning it to the caller of the new Promise
constructor. But the Promise constructor completely ignores a return value, if any. It's kind of like returning something when iterating in forEach
- it just gets ignored.
In order to resolve a Promise constructed via the Promise constructor, you must call the first argument provided to the callback (which is conventionally named resolve
, but may be named anything you want).
Also note that there's no need at all to wrap the rejection in new Error
- if you just have a string message to send to the consumer, it's fine to reject with just a string.
function readFile(path) {
return new Promise(function(resolve, reject){
if(!fs.existsSync(path))
reject("data.json file does not exist");
else {
console.log("File is actually found!");
resolve("File found");
}
})
}
Which is equivalent to:
function readFile(path) {
return new Promise((fnToCallToResolveConstructedPromise, fnToCallToRejectConstructedPromise) => {
if(!fs.existsSync(path))
fnToCallToRejectConstructedPromise("data.json file does not exist");
else {
console.log("File is actually found!");
fnToCallToResolveConstructedPromise("File found");
}
})
}
You can wrap it in an error object if it provides useful info for you, aside from the string describing the error, but otherwise, best to omit it, and just call reject
with a string.
Related Topics
How to Save HTML Page as PDF Using JavaScript or Jquery
Determine Which Element the Mouse Pointer Is on Top of in JavaScript
Finding Variable Type in JavaScript
JavaScript for "Add to Home Screen" on Iphone
Simple Function to Sort an Array of Objects
Most Efficient Method of Detecting/Monitoring Dom Changes
Angular 2 Dependency Injection in Es5 and Es6
How to Convert a String of Numbers to an Array of Numbers
Playing Sound Notifications Using JavaScript
JavaScript Read File Without Using Input
Dynamic Template Urls in Angular 2
Download a Div in a HTML Page as PDF Using JavaScript
JavaScript Regexp Dynamic Generation from Variables