我开始使用Promise链接,我正在使用express和mongoose在节点中尝试一些代码。这是我的代码:
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);
});
};
这是一个注册用户并向他发送令牌的简化代码。我想要做的是,首先,检查用户是否已经注册,如果没有,请注册。
正如你所看到的,第6行是错误的,我认为,因为我没有返回任何Promise,所以在第4行之后,代码继续执行。我想避免回调地狱,我怎么能做到这一点?感谢
答案 0 :(得分:3)
您没有返回Promise
这一事实并不重要。 then()
和catch()
的返回值会自动包含在Promise
个对象中。
问题在于您的流是线性的(它遵循直线路径),但您正在尝试分支,以便某些部分仅在某些情况下运行。您需要两个执行路径:
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);
});
};
如果您想避免深度嵌套,您有两种选择:
将不同的路径封装到函数中,这样您就可以执行以下操作:
if (user) {
return sendHttpError(res, 409)
} else {
return sendNewUser(res, req.body)
}
也许只需要sendHttpError
功能,而另一条可能的路径可能是路线的主体。这是非常标准的。
由于您的某个分支只处理错误情况,您可以抛出Error
并在下面捕获它,或者在错误处理中间件中。它看起来像这样:
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 normally
这也是一种非常常见的模式。
答案 1 :(得分:2)
如果用户已存在,则只需抛出error
即可直接转到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);
});
};