What's the Difference Between Returning Value or Promise.Resolve from Then()

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.

  1. 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.
  2. Promise.resolve().then(() => API(/*...*/)) Produce several Promise instances: one at Promise.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.
  3. 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



Leave a reply



Submit