What's the difference between returning value or Promise.resolve from then()
What is the difference between:
new Promise(function(res, rej) {
res("aaa");
})
.then(function(result) {
return "bbb";
})
.then(function(result) {
console.log(result);
});
and this:
new Promise(function(res, rej) {
res("aaa");
})
.then(function(result) {
return Promise.resolve("bbb");
})
.then(function(result) {
console.log(result);
});
I'm asking as I'm getting different behaviour Using Angular and $http service with chaining .then(). A bit too much code hence first the example above.
Solution 1:
In simple terms, inside a then
handler function:
A) When x
is a value (number, string, etc):
-
return x
is equivalent toreturn Promise.resolve(x)
-
throw x
is equivalent toreturn Promise.reject(x)
B) When x
is a Promise that is already settled (not pending anymore):
-
return x
is equivalent toreturn Promise.resolve(x)
, if the Promise was already resolved. -
return x
is equivalent toreturn Promise.reject(x)
, if the Promise was already rejected.
C) When x
is a Promise that is pending:
-
return x
will return a pending Promise, and it will be evaluated on the subsequentthen
.
Read more on this topic on the Promise.prototype.then() docs.
Solution 2:
The rule is, if the function that is in the then
handler returns a value, the promise resolves/rejects with that value, and if the function returns a promise, what happens is, the next then
clause will be the then
clause of the promise the function returned, so, in this case, the first example falls through the normal sequence of the thens
and prints out values as one might expect, in the second example, the promise object that gets returned when you do Promise.resolve("bbb")
's then is the then
that gets invoked when chaining(for all intents and purposes). The way it actually works is described below in more detail.
Quoting from the Promises/A+ spec:
The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as
[[Resolve]](promise, x)
. Ifx
is a thenable, it attempts to make promise adopt the state ofx
, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the valuex
.This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.
The key thing to notice here is this line:
if
x
is a promise, adopt its state [3.4]link: https://promisesaplus.com/#point-49
Solution 3:
Both of your examples should behave pretty much the same.
A value returned inside a then()
handler becomes the resolution value of the promise returned from that then()
. If the value returned inside the .then
is a promise, the promise returned by then()
will "adopt the state" of that promise and resolve/reject just as the returned promise does.
In your first example, you return "bbb"
in the first then()
handler, so "bbb"
is passed into the next then()
handler.
In your second example, you return a promise that is immediately resolved with the value "bbb"
, so "bbb"
is passed into the next then()
handler. (The Promise.resolve()
here is extraneous).
The outcome is the same.
If you can show us an example that actually exhibits different behavior, we can tell you why that is happening.
Solution 4:
You already got a good formal answer. I figured I should add a short one.
The following things are identical with Promises/A+ promises:
- Calling
Promise.resolve
(In your Angular case that's$q.when
) - Calling the promise constructor and resolving in its resolver. In your case that's
new $q
. - Returning a value from a
then
callback. - Calling Promise.all on an array with a value and then extract that value.
So the following are all identical for a promise or plain value X:
Promise.resolve(x);
new Promise(function(resolve, reject){ resolve(x); });
Promise.resolve().then(function(){ return x; });
Promise.all([x]).then(function(arr){ return arr[0]; });
And it's no surprise, the promises specification is based on the Promise Resolution Procedure which enables easy interoperation between libraries (like $q and native promises) and makes your life overall easier. Whenever a promise resolution might occur a resolution occurs creating overall consistency.