I am not really sure I understand the difference between these two common scenarios.
Say we have this:
user.save().then(function(val){
anotherPromise1(val);
}).then(function(val){
anotherPromise2(val);
}).catch(function(err){
});
versus:
user.save().then(function(val){
return anotherPromise1(val);
}).then(function(val){
return anotherPromise2(val);
}).catch(function(err){
});
I know it makes a difference but how exactly?
If you don't return a value from the then
callback, you're effectively returning undefined
. The next then
callback will run immediately, and see undefined
as the resolution value.
If you return a promise from the then
callback, the second then
callback waits on that promise (indirectly, but that doesn't really matter), and when that promise is resolved, gets the resolution value from that promise.
(This is covered by the then
specification in the Promises/A+ spec, but slightly by omission — it doesn't explicitly mention what should happen if onFulfilled
doesn't return anything, but in JavaScript, calling a function always gives you a resulting value; if the function doesn't explicitly return something, undefined
is the result of calling it. JavaScript doesn't have the concept of void
methods a'la C/C#/C++/Java.)
You can see it in this script live copy on Babel's REPL:
let start = Date.now();
function elapsed() {
let rv = String(Date.now() - start);
while (rv.length < 4) {
rv = "0" + rv;
}
return rv;
}
function anotherPromise(type, val) {
console.log(`${elapsed()}: anotherPromise[${type}] got ${val}`);
return new Promise(resolve => {
setTimeout(() => { resolve(val * 2); }, 1000);
});
}
function anotherPromise2(type, val) {
console.log(`${elapsed()}: anotherPromise2[${type}] got ${val}`);
return new Promise(resolve => {
setTimeout(() => { resolve(val * 3); }, 10);
});
}
let user = {
save: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(42);
}, 10);
});
}
}
// Without return
user.save().then(function(val){
anotherPromise("without", val);
}).then(function(val){
anotherPromise2("without", val);
}).then(function() {
console.log(`${elapsed()}: All done`);
}).catch(function(err){
});
user.save().then(function(val){
return anotherPromise("with", val);
}).then(function(val){
return anotherPromise2("with", val);
}).then(function() {
console.log(`${elapsed()}: All done`);
}).catch(function(err){
});
The output is (for example):
0015: anotherPromise[without] got 42
0017: anotherPromise2[without] got undefined
0018: All done
0020: anotherPromise[with] got 42
1021: anotherPromise2[with] got 84
1032: All done
Note the differences between without a return and with a return:
Without, anotherPromise2
was called immediately (as we can see from the elapsed time values) and received undefined
.
With, anotherPromise2
waited for anotherPromise
's resolution to occur, and then received 84
(anotherPromise
's resolution value)
The difference is the timing in this matter.
In example 1, the save
promise is fullfilled and the anotherPromise1
will be invoked and because there is no promise returned, the anotherPromise2
will be invoked immediately.
If you return the promise of the anotherPromise1
function, the invokation of anotherPromise
will happen, after anotherPromise1
was resolved.
So example 1: anotherPromise1
and anotherPromise2
will be shot simultaneous
While example 2: anotherPromise2
will wait for anotherPromise1
to be resolved