如何使用承诺将语句链接在一起

how to chain statements together using promises

我是节点的新手,正在学习所有关于承诺的知识,特别是 pg-promise。这就是我想用 Express 和 pg-promise:

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

我已经设置了我的回购协议 (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-promise 不会像这样链接在一起?它们应该相互嵌套还是完全独立的块?另外,不太确定问题在哪里。我已经按照各种教程尝试了所有我能想到的方法,但我收到诸如“无法设置已经设置的 headers”和“未 returned 承诺”之类的错误。如果哪位好心人能指点一下,感激不尽

检查usernameemail的存在是相互独立的。我认为 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
  });

};

执行多个查询时必须使用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 says you should do. See Tasks versus root/direct queries

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

在 vitaly-t 的指导下,我修改了他的答案,根据失败的内容包含单独的错误消息。我还将下一个 "then" 上移到事务块中,以便在创建用户的下一步中使用事务的 "t"。非常感谢 vitaly-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});
});