【问题标题】:how to chain statements together using promises如何使用 Promise 将语句链接在一起
【发布时间】:2017-02-05 09:47:06
【问题描述】:

我是 node 新手,正在学习所有关于 Promise 的知识,特别是 pg-promise。这就是我想要使用 Express 和 pg-promise 做的事情:

  1. 检查电子邮件,
  2. 如果找不到,请检查用户名,
  3. 如果找不到,请创建一个新用户。
  4. 返回用户ID

我已经设置了我的 repo (db.users),它执行的 sql 运行良好。

在我的授权处理程序中,我不确定如何使 repo 调用彼此跟随。语法对我来说似乎很笨拙。到目前为止,这是我所拥有的:

exports.signup = function( req, res, next ) {

const username = req.body.username;
const email = req.body.email;
const password = req.body.password;

 // See if a user with the given email exists
     db.users.byEmail({email: email})
      .then(user => {
        if (user) {
         return res.status(422).send({ error: 'Email is in use'});
       } else { 
         return null;   <-- must I return something here?
       }
      })
   .then(() => {
     db.users.getUsername({username: username})
     .then(user => {
        if (user) {
         return res.status(422).send({ error: 'Email is in use'});
       } else { 
         return null;   <-- must I return something here?
       }

       ...etc

   })

也许 pg-promises 不会像这样链接在一起?它们应该相互嵌套还是完全独立的块?此外,不太确定捕获的位置。按照各种教程,我已经尝试了所有我能想到的方法,但是我收到了诸如“无法设置已设置的标头”和“未返回承诺”之类的错误。如果哪位好心人能在这里指导我,我将不胜感激。

【问题讨论】:

    标签: node.js express pg-promise


    【解决方案1】:

    执行多个查询时必须使用task,这样它们才能共享一个连接,否则连接管理会出现性能问题。

    db.task(t => {
        return t.users.byEmail({email})
            .then(user => {
                return user || t.users.getUsername({username});
            });
    })
        .then(user => {
            if (user) {
                res.status(422).send({error: 'Email is in use'});
            } else {
                // do something else
            }
        })
        .catch(error => {
            // process the error
        });
    

    假设您的存储库已按照pg-promise-demo 中所示设置,它将运行良好。

    前面的 2 个答案是非常糟糕的建议,完全违背了 pg-promise 所说的你应该做的事情。见Tasks versus root/direct queries。

    当进行多项更改时,您通常会使用事务 - 使用 tx 而不是 task。

    【讨论】:

    • 感谢您帮助我。这很有帮助,但我有一个问题。我想为每个失败返回一个单独的错误。如果该电子邮件有记录,我想返回“电子邮件正在使用”和用户名的不同错误。从我从您的代码中可以看出,它只返回一个电子邮件错误。我该怎么做?
    【解决方案2】:

    在vitally-t 的指导下,我更改了他的答案,根据失败的情况包含单独的错误消息。我还将下一个“then”上移到事务块中,以便将事务的“t”用于创建用户的下一步。非常感谢vitally-t!

    db.task(t => {
        return t.users.byEmail({email})
          .then(user => {
              if (user) {
                throw new Error('Email is in use');
              } else {
                return t.users.byUsername({username});
            }
          })
          .then((user) => {
              if (user) {
                  throw new Error('Username is taken');
              } else {
                  return t.users.addNew({username, email, password});
              }
          })
    })
    .then(user => {
        res.json({token: tokenForUser(user), username: user.username, aCheck: user.is_admin});
    })
    .catch(error => {
        res.status(422).json({ 'error': error.message});
    });
    

    【讨论】:

      【解决方案3】:

      检查username 和email 的存在是相互独立的。我认为Promise.all() 比顺序链接承诺更适合您的需要。

      exports.signup = function (req, res, next) {
        const username = req.body.username;
        const email = req.body.email;
        const password = req.body.password;
      
        Promise.all([
          db.users.byEmail({
            email: email
          }),
          db.users.getUsername({
            username: username
          })
        ]).then((results)=> {
          if (results[0] || results[1]) {
            return res.status(422).send({
              error: 'Email is in use' // same error msg as per your snippet
            });
          }
          // here, code for creating a new user
        });
      
      };
      

      【讨论】:

      • 这正是pg-promise 文档告诉我们永远不要做的事情:github.com/vitaly-t/pg-promise/wiki/…。如果这还不够糟糕,他的查询是依赖的,它们不能独立执行。
      • @vitaly-t 是的。你说的对。感谢您指出。支持你回答
      猜你喜欢
      • 2017-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多