【问题标题】:How can I fix this ES6 promise chain in Express?如何在 Express 中修复这个 ES6 承诺链?
【发布时间】: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 行之后,代码继续执行。我想避免回调地狱,我该如何做到这一点?谢谢

【问题讨论】:

    标签: javascript express mongoose ecmascript-6 promise


    【解决方案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);
      });
    };
    

    如果你想避免深度嵌套,你有两种选择:

    1. 将不同的路径封装成函数,这样你就可以这样做:

      if (user) {
        return sendHttpError(res, 409)
      } else {
        return sendNewUser(res, req.body)
      }
      

    也许只有sendHttpError函数是必需的,其他可能的路径可以是你路由的主体。这是相当标准的。

    1. 由于您的一个分支仅处理错误情况,您可以抛出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 } })
    猜你喜欢
    • 2016-06-13
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 2017-06-03
    • 2016-08-06
    • 1970-01-01
    相关资源
    最近更新 更多