【问题标题】: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 中的正确方法是什么?

【问题讨论】:

    标签: javascript json node.js error-handling 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);
        })
        

        【讨论】:

        • 如果你坚持使用 new Promise 构造函数,要么将 User.findOne 承诺放在 then 处理程序之后,要么在最后调用 resolve(User.findOne(…))
        猜你喜欢
        • 2016-02-26
        • 2018-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-08
        • 1970-01-01
        相关资源
        最近更新 更多