如何在Express中修复此ES6承诺链?

时间:2017-04-27 14:31:41

标签: javascript express mongoose ecmascript-6 promise

我开始使用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行之后,代码继续执行。我想避免回调地狱,我怎么能做到这一点?感谢

2 个答案:

答案 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);
  });
};

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

  1. 将不同的路径封装到函数中,这样您就可以执行以下操作:

    if (user) {
      return sendHttpError(res, 409)
    } else {
      return sendNewUser(res, req.body)
    }
    
  2. 也许只需要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
      
    2. 这也是一种非常常见的模式。

答案 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);
  });
};