Could someone explain to me why returning promises in promises callbacks is considered antipattern? Apparently it breaks exception bubbling but obviously my understanding of promises is lacking as I cannot clearly picture how would that work. My antipattern code is below:
var a = new Promise(function (res, rej) {
setTimeout(function () {
res("timeout");
}, 1000);
});
a.then(function (res) {
console.log("a");
console.log(res);
return new Promise(function (res, rej) {
console.log("b");
setTimeout(function () {
res("timeout2");
}, 2000);
}).then(function (res) {
console.log("c");
console.log(res);
}).then(function (res) {
console.log("d");
console.log(res);
}, function (res) {
console.log("e");
console.log(res);
});
}).then(function (res) {
console.log("l");
console.log(res);
});
EDIT:
This question is related to one of my previous questions where I do something similar with promises and one of the answers says:
"You must also never mix callbacks with promises because then you lose exception bubbling (the point of promises) and make your code super verbose."
So now I'm really confused if it is antipattern and if so why.
"You must also never mix callbacks with promises because then you lose exception bubbling (the point of promises) and make your code super verbose."
What Petka means here, is that you should not use callback based methods in your user code together with Promises because this will make your code very verbose, as illustrated by your example.
It's verbose because you have to manually resolve or reject a new Promise based on the callback every time you call the function.
setTimeout Example:
You have to manually call the resolver when the timeout completes.
Now setTimeout is a bit of a poor example as it does not have a possibility to reject it's operation.
return new Promise(function (resolve, reject) {
console.log("b");
setTimeout(function () {
resolve("timeout2");
}, 2000);
})
Better example
Say you want to call fs.readFile
like so:
return new Promise(function (resolve, reject) {
fs.readFile('foo.txt', function (err, res) {
if (err){
reject(err);
return;
} else {
resolve(res);
}
});
})
Here you have to ether resolve or reject because you are mixing promises with callbacks, this will make your code very brittle and confusing.
Solution:
Instead of creating new Promises all over the place whenever you need to call a method that only supports callbacks, wrap that callback based method once and use that everywhere.
var readFileAsync = new Promise(function (resolve, reject) {
fs.readFile('foo.txt', function (err, res) {
if (err){
reject(err);
return;
} else {
resolve(res);
}
});
});
Bonus:
You don't even need to do this wrapping your self, bluebird has got you covered.
Checkout promisification right here:
https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification
This whole explanation is sort of beside the fact that it is completely valid to return a Promise inside a promise's onFulfilled
method.
This is part of the Promise/A+ spec, see the The Promise Resolution Procedure
-> 2.3.2 If x is a promise, adopt its state [[3.4](#notes)]:
I assume your confusion originates from the fact that Petka is telling you not to create and return new promises in your example. But this has nothing to do with the fact that you are returning Promises, but rather with the fact that you shouldn't be creating promises at that place, as stated here above.
Use a wrapped version, and then you are good to return/chain them wherever you want.