如何在 Express 中修复这个 ES6 承诺链?
Posted
技术标签:
【中文标题】如何在 Express 中修复这个 ES6 承诺链?【英文标题】:How can I fix this ES6 promise chain in Express? 【发布时间】:2017-09-25 10:10:07 【问题描述】:我从 Promise 链接开始,我正在尝试在 node.js 中使用 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 行之后,代码继续执行。我想避免回调地狱,我该如何做到这一点?谢谢
【问题讨论】:
【参考方案1】:您没有返回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
这也是一种很常见的模式。
【讨论】:
那么,这里不可能有 Promise 链吧? 从逻辑上讲,您需要一个分叉链,但不一定嵌套在代码的书面文本中。我添加了两种可能的策略来避免在答案中嵌套回调。【参考方案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);
);
;
【讨论】:
是的,这是一个可能的答案,但我忘了说我只使用 catch 块来捕获运行时错误 您可以指定要抛出的错误,以便将运行时错误与您的错误区分开来。throw new Error( foo: 'bar', ...);
catch(err => if (err.foo === 'bar') // this is your error else // runtime error )
以上是关于如何在 Express 中修复这个 ES6 承诺链?的主要内容,如果未能解决你的问题,请参考以下文章
原生 ES6 承诺中 Bluebird Promise.finally 的等价物是啥? [复制]