The problem is that when you recursively call getNextUsername()
you are not resolving the outer-most Promise. That call will spawn a new Promise and (maybe) that will be resolved but the value will go nowhere as it's not used.
Since getNextUsername()
does produce a Promise and it (hopefully) resolves with a value, you can very simply amend your code by adding the resolution step:
const getNextUsername = () => {
return new Promise((res, rej) => {
Counter.findByIdAndUpdate('usernames', {
$inc: {
sequence: 1
}
}, {
upsert: true,
new: true
}, (err, result) => {
if (err) rej(err);
User.findOne({
username: result.sequence
}, (err, u) => {
if (err) rej(err);
if (u) {
//after the recursive call completes, resolve with the returned value or fail if it failed
getNextUsername()
.then(res)
.catch(rej);
} else {
res(result.sequence);
}
})
})
})
}
This way, when the subsequent Promise is resolved, you'd propagate the resolved value out of the Promise. Regardless of how many promises down you are, this should work even if you have Promise1 -> Promise2 -> Promise3 when the third one resolves, the second will then call .then(res)
and return the value, which will again call .then(res)
in the first Promise and push the value out.
The .catch(rej)
will do a similar thing but with errors - if any inner promise fails, all the ones to the top will fail.
Here is a very simple implementation of recursive functions using Promises just to illustrate the idea:
function recursiveSum(a, b, debugPrefix = ">") {
return new Promise((res, rej) => {
console.log(debugPrefix, "recursively summing", a, b);
if (b <= 0) {
console.log(debugPrefix, "result found");
res(a);
} else {
console.log(debugPrefix, "going deeper");
recursiveSum(a+1, b-1, debugPrefix + ">")
.then(res);
}
})
}
recursiveSum(5, 3)
.then(console.log);
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…