Re:Never Mix Promises and Callbacks in NodeJS
by ascagnel_ on Friday April 07, 2017 @12:24PM
(#14061054)
If you must call the callback, you could simplify this pattern as such:
function fetchFirstUser(isWhatIWant, callback) {
knex.first().from('users')
.then(user => ({ user }))
.catch(e => ({ e }))
.then(({ user, e }) => {
if (user) {
callback(user);
} else {
callback(e);
}
});
}
By only calling your callback function after a catch statement, you guarantee that (a) an exception generated by the callback will not be swallowed by the catch statement and that (b) the callback is called exactly once in the promise chain.
Re:Never Mix Promises and Callbacks in NodeJS
by spankalee on Friday April 07, 2017 @12:55PM
(#14061354)
I like this!
For golfing purposes, you can remove a branch too:
function fetchFirstUser(isWhatIWant, callback) {
knex.first().from('users')
.then((user) => ({ user }), (e) => ({ e }))
.then(({ user, e }) => callback(e, user))
.catch((e) => console.error(e));
}
Re:Never Mix Promises and Callbacks in NodeJS
by Vevolut on Friday April 07, 2017 @12:53PM
(#14061343)
I may be mistaken but I don't think this will work exactly how you expect it to. If theres an unhandled exception thrown somewhere in the callback then it will fail silently. You need to add a .catch(console.error.bind(console)); at the very end to get back to default behavior.
The problem here is that chained Promise reactions, like .then(A).catch(B) can indeed call both A and B if A throws, which in this case is very bad if you can only call one of them.
The correct solution is to use an error handler in .then():
But anytime you're invoking callbacks you also have to consider the case where the callback throws - which is one reason returning Promises is generally easier to get correct than invoking callbacks - so you _also_ need a .catch(): This might seem like a lot, but I blame callbacks in general for the extra work that needs to be done. If you can avoid callbacks, do, because Promises all the way through would be so much simpler: And push error handling out to the initiator.