在节点中使用psql(pg-promise)在for loops / promise.all内部承诺

Ron*_*n I 3 javascript node.js psql ecmascript-6 pg-promise

您好,我是Promises的新手,他被困在如何等待for循环中的所有promise解析之后再转到下一个then()。我已经看到了两个promise.all示例,但是我不清楚如何使它们适应下面的代码。当前,它转到for循环之后的下一个then(),并在for循环完成之前进行解析。任何帮助表示赞赏!

我正在使用pg-promise(带有承诺的psql)。

原始代码:

function getTeamMembers(aTeam) {
    let promise = new Promise(function(resolve, reject) {
      db.getTeamMembers(aTeam.tid) //return sql results rows
        .then(function(rows){
          for(let i=0; i<rows.length; ++i) { //loop through each result row
            getUserByUsername(rows[i].username)
              .then(function(cfUser) { //add user from row to aTeam object                    
                aTeam.addMember(cfUser);
              })
              .catch(function(e) {
                reject(e);
              });
          }
        })
        .then(function(){
          console.log(aTeam); //confirm added properly
          resolve(aTeam); //resolve object
        })
        .catch(function(e) {
          console.log('addMemberToTeamByUsername: '+e.stack);
          reject(e);
        });
    });
    return promise;
  }
Run Code Online (Sandbox Code Playgroud)

vit*_*y-t 5

我是pg-promise的作者。

以下是有关Promise.all在此上下文中无效使用答案的一些注意事项,该答案现已删除。


使用表示物理资源的基于承诺的接口时,重要的是要了解所使用的物理上下文。没有它,您可能会因为物理资源无法像您的通用承诺解决方案那样规模扩展这一简单事实而陷入瓶颈。

如果pg-promise您的身体状况由两部分组成:

  • 查询要通过Node.js IO传递的字符串
  • 连接池提供的连接上下文

每个查询请求从连接池获取并释放连接,这是非常有限的物理资源。池的默认大小为10,由基础驱动程序设置node-postgres。尽管可以将其增加到最多100个,但这样做会开始在连接管理上造成过载,因此它的可伸缩性并不那么好。通常将增量设置为20,这大约是平均值。

因此,如果您Promise.all在查询数组上使用,则应用程序几乎会立即耗尽该池,并且对服务的下一个请求都将坐在那里等待可用的连接。

这种解决方案根本无法扩展,并且在此处被列为查询执行的反模式:任务与根/直接查询

基本上,这说明您必须通过任务执行多个查询:

  • 方法任务,如果您不更改数据
  • 方法tx(交易),如果您要更改数据

这样,您可以通过单个连接通过管道传输所有查询,这对于实现服务的可伸缩性至关重要。


通过示例学习”教程中有很多示例,分别针对“ 任务”和“ 事务”


考虑到您尝试获取多个父行,然后获取多个子行,您应该看一下这个问题:使用PostgreSQL / NodeJS将JOIN表作为结果数组

我也建议阅读Performance Boost文章,以更好地理解执行多重查询的物理限制以及如何解决它们。

function getTeamMembers(aTeam) {
    return db.task(t=> {
        return t.map('SELECT * FROM team_members WHERE id=$1', aTeam.id, tm=> {
            return t.any('SELECT * FROM users WHERE name=$1', tm.username)
                .then(users=> {
                    tm.users = users;
                    return tm;
                });
        }).then(t.batch);
    });
}

// usage example:

getTeamMembers({id: 123})
    .then(members=> {
        // members = array of member objects
    })
    .catch(error=> {
        // error
    });
Run Code Online (Sandbox Code Playgroud)

这不是唯一的方法,但是它是最短的;)

在以下问题中对这种方法进行了更好的考虑:使用PostgreSQL / NodeJS将JOIN表作为结果数组