在承诺之外抛出错误
Posted
技术标签:
【中文标题】在承诺之外抛出错误【英文标题】:Throw errors outside of promise 【发布时间】:2018-02-19 11:00:01 【问题描述】:我有一个功能来登录一个应该返回 JSON 的用户。
const username = req.body.username;
const password = req.body.password;
if (!username)
throw new Error('Missing username');
if (!password)
throw new Error('Missing password');
User.findOne( username, password ).then(user =>
res.json( user );
).catch(err =>
res.json( err );
);
但是在 JSON 中不返回缺少用户名或缺少密码的错误。
我可以改成
const username = req.body.username;
const password = req.body.password;
if (!username)
res.json( err: 'Missing username' );
if (!password)
res.json( err: 'Missing password' );
User.findOne( username, password ).then(user =>
res.json( user );
).catch(err =>
res.json( err );
);
不过好像有点多余。
将其封装在 Promise 中的正确方法是什么?
【问题讨论】:
【参考方案1】:在您的第一个解决方案中,将不会处理抛出的错误,因为您将它们抛出承诺链之外并且没有 try/catch
块。在您的第二个解决方案中,您可能会收到 cannot send headers after they sent
错误,因为可以发送两次响应(username
缺失和 password
缺失)。
所以这里可能的解决方案之一是创建一个承诺链(使用Promise.resolve()
)并在此处验证参数:
function validateParams()
const username = req.body.username;
const password = req.body.password;
if (!username)
throw new Error('Missing username');
if (!password)
throw new Error('Missing password');
return username, password ;
Promise
.resolve()
.then(validateParams)
.then(filter => User.findOne(filter))
.then(user => res.json(user))
.catch(err => res.json(err));
【讨论】:
在您的示例中,您应该包括对validateParams
的调用 :)
对于阅读这篇文章的人来说,.then(validateParams)
相当于.then(() => validateParams())
【参考方案2】:
显而易见的方法确实是将它们封装在一个 Promise 中以启动你的 Promise 链(User.findOne
在第一个 then
块内)——这样你当前的错误处理程序就可以很好地捕获它们。
【讨论】:
【参考方案3】:我以@alexmac 为例并使用 es6 异步功能:
function validateParams()
const username = req.body.username;
const password = req.body.password;
if (!username)
throw new Error('Missing username');
if (!password)
throw new Error('Missing password');
return username, password ;
async function resolver()
try
await resolve()
let filter = validateParams()
let user = await User.findOne(filter)
await res.json(user)
catch (e)
await res.json(e)
使用if
而不是throw
会看起来更优雅:
async function(req, res)
const password = req.body.password
const username = req.body.username
let c = !password ? 'missing password' :
!username ? 'missing username' : null
if (!c)
c = await User.findOne( username, password )
await res.json(c)
【讨论】:
【参考方案4】:你可以将你的函数包装在一个 Promise 中并有效地处理它
function getRes()
return new Promise(function(resolve, reject)
const username = req.body.username;
const password = req.body.password;
if (!username)
reject(new Error('Missing username'));
if (!password)
reject(new Error('Missing password'));
resolve(User.findOne( username, password ));
);
getRes().then(function(result)
res.json(result);
).catch(function(err)
res.json(err);
)
【讨论】:
避免Promise
constructor antipattern!
如果你坚持使用 new Promise
构造函数,要么将 User.findOne
承诺放在 then
处理程序之后,要么在最后调用 resolve(User.findOne(…))
。以上是关于在承诺之外抛出错误的主要内容,如果未能解决你的问题,请参考以下文章