Estoy comenzando con el encadenamiento de Promise y estoy probando un código usando express y mongoose en node. Este es mi código:
const register = (req, res, next) => { User.findOne(req.params.email).exec().then(user => { if (user) { return res.status(409).json({ error: 409 }); } return User.create(req.body); }).then(user => { const token = jwt.sign({ sub: user._id }, 'test-secret'); return res.status(200).json({ token }); }).catch(err => { return next(err); }); };Este es un código simplificado para registrar a un usuario y enviarle un token. Lo que quiero hacer es, primero, comprobar si el usuario ya está registrado y, en caso contrario, registrarlo.
Como puede ver, creo que la línea 6 está mal, porque no estoy devolviendo ninguna Promesa, por lo que después de la línea 4, el código continúa ejecutándose. Quiero evitar el infierno de devolución de llamada, ¿cómo puedo lograr esto? Gracias
El hecho de que no estés devolviendo una Promise no es importante. Los valores de retorno de then() y catch() se envuelven automáticamente en objetos Promise .
El problema es que su flujo es lineal (sigue un camino recto), pero está tratando de bifurcarse para que algunas partes solo se ejecuten en algunos casos. Necesita dos rutas de ejecución:
const register = (req, res, next) => { User.findOne(req.params.email).exec().then(user => { if (user) { // Path 1 stops here: return res.status(409).json({ error: 409 }); } else { // Path 2 continues down this 2nd Promise chain: return User.create(req.body).then(user => { const token = jwt.sign({ sub: user._id }, 'test-secret'); return res.status(200).json({ token }); }) } }).catch(err => { // Both paths converge on this error handler return next(err); }); };Si desea evitar el anidamiento profundo, tiene dos opciones:
Encapsule las diferentes rutas en funciones, para que luego pueda hacer algo como esto:
if (user) { return sendHttpError(res, 409) } else { return sendNewUser(res, req.body) } Quizás solo sea necesaria la función sendHttpError , y la otra ruta posible puede ser el cuerpo principal de su ruta. Esto es bastante estándar.
Dado que una de sus sucursales solo se ocupa de los casos de error, puede generar un Error y capturarlo a continuación, o en un middleware de manejo de errores. Se vería así:
if (user) { // This throw will abort execution of everything that follows. By // using a custom Error class, you can then handle it appropriately // in a catch() handler or Express middleware: throw new APIError(409) } // ... create user and proceed normallyEste también es un patrón muy común.
Simplemente arroje un error si el usuario ya existe para ir directamente a la función de catch .
const register = (req, res, next) => { User.findOne(req.params.email).exec().then(user => { if (user) { throw new Error({ error: 409, msg: 'User already exists' }); } return User.create(req.body); }).then(user => { const token = jwt.sign({ sub: user._id }, 'test-secret'); return res.status(200).json({ token }); }).catch(err => { return next(err); }); };