对于循环/ promise.all内部的promise,在节点中使用psql(pg-promise)

时间:2016-10-14 02:45:29

标签: javascript node.js ecmascript-6 psql pg-promise

你好,我是Promises的新手,并坚持如何等待for循环中的所有promises在进入下一个then()之前解决。我已经看到了几个promise.all示例,但我不清楚如何根据以下代码调整它们。它目前转到for循环后的next(),并在for循环完成之前解析。任何帮助表示赞赏!

我正在使用pg-promise(psql with promises)。

原始代码:

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;
  }

1 个答案:

答案 0 :(得分:4)

我是pg-promise的作者。

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

使用表示物理资源的基于承诺的界面时,了解所使用的物理上下文非常重要。如果没有它,您就有可能遇到瓶颈,因为物理资源不像您的通用承诺解决方案那样扩展。

如果pg-promise你的物理背景由两件事组成:

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

每个查询请求从连接池获取和释放连接,连接池是非常有限的物理资源。池的默认大小为10,由底层驱动程序node-postgres设置。虽然您可以将其增加到100,但这样做会开始在连接管理上创建过载,因此它不具有可扩展性。典型的增加量应设为20,约为平均值。

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

这样的解决方案根本无法扩展,它在此处列为查询执行的反模式:Tasks versus root/direct queries

基本上,它解释的是你必须通过任务执行多个查询:

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

通过这种方式,您可以通过单个连接传输所有查询,这对于实现服务的可扩展性至关重要。

Learn By Example教程中有很多关于TasksTransactions的示例。

考虑到你试图获得多个父行,然后是多个子行,你应该看看这个问题:get JOIN table as array of results with PostgreSQL/NodeJS

我还建议阅读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
    });

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

在以下问题中,我们会更好地考虑这种方法:get JOIN table as array of results with PostgreSQL/NodeJS