If you want to chain a promise with an API that has callbacks I recommend you use pify or one of the methods of another library of promises like bluebird.promisify . Note that these only work for node style callbacks, that is
callback((error, data) => {})
As for why your code is printing 123
is very simple. You must understand that the promises when they are chained have two channels, the success
and the error
. A "chain of promises" in the rejected state can "recover" and another in a successful state can be "rejected" by changing the channel in which it is located. It is worth emphasizing that I am not only talking about promises but about the chain of these.
A crucial part of all this is the value you return from the method then
When you return a value either in then
or% catch
it automatically becomes a promise resolved . You can check it in the following snippet (eye you need a compatible browser)
const a = new Promise((resolve, reject) => {
reject('reason')
})
.catch(() => {
console.log(1);
return 2;
})
.then((val) => {
console.log(val);
});
If you notice, I am returning a value within a catch
and this became a resolved promise and therefore entered the next then
. A very common mistake is to think that returning an error will keep the string in the catch
section.
If you want your chain to jump to the next catch
of the string you should launch an error
const a = Promise
.reject().catch(() => {
console.log(1);
throw new Error();
}).then(() => {
console.log(2);
}).catch(() => {
console.log(3);
});
See how it jumps from a catch
to the other without going through the then
. The same does not happen if you only return an error
const a = Promise
.reject().catch(() => {
console.log(1);
return new Error(1);
}).then(() => {
console.log(2);
}).catch(() => {
console.log(3);
});
In this case, print 1 returns a promise results and then jump to then
by printing 2, omitting the catch
or error channel.
Summing up a string "rejected" can be retrieved in the next step by just returning a value or another string that resolves to anything in its last step and a string " resolved "can be rejected by throwing an error or returning another string that completes in the rejected state.
According to the documentation findById
returns a Query
that has a method then
that makes it a promise. Do not confuse it with the same method then
of these. Read this article so you can understand the difference. The method exec
if gives you a promise. Instead of this
new Promise((resolve,reject) => {
User.findById(idUserSender, (err,userFound) => {
if (err) {
reject(err)
} else {
resolve(userFound)
}
});
})
You can only write
return User.findById(idUserSender).exec(); // Esta es una promesa lista para encadenar
As an additional note I will tell you that all this behavior is defined in the spec A + of the promises. The promises of the browsers and node on the server (which are defined in the spec of javascript) are conformant with the A +. There are some promises (very few currently) that do not implement said spec so the behavior could vary but it is usually obsolete libraries.