【问题标题】:Promises inside for loops / promise.all, using psql (pg-promise) in nodefor loops / promise.all 中的 Promise,在节点中使用 psql (pg-promise)
【发布时间】:2017-02-23 08:26:55
【问题描述】:

您好,我是 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;
  }

【问题讨论】:

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


    【解决方案1】:

    我是pg-promise的作者。

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


    在使用代表物理资源的基于 Promise 的接口时,了解所使用的物理上下文非常重要。如果没有它,您可能会遇到瓶颈,因为物理资源无法像您的通用承诺解决方案那样扩展。

    如果是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

    【讨论】:

    • 我想知道是谁投了反对票。但也许你应该添加一些代码?
    • @Bergi,是的,我忙着回答,下班了,有机会会进一步详细说明。也被第一答案作者的批评绊倒了(现已删除)。我猜这只是糟糕的一天。
    • 嗨 Vitaly - 你能提供一些代码作为例子吗?我很想看看!我会查看您的建议,感谢您帮助提升我的知识和代码!
    • @RonI 刚刚做了。但实际上,考虑一下这里发布的内容:stackoverflow.com/questions/39805736/…
    • 不幸的是,我收到以下错误:错误:没有参数 $1
    猜你喜欢
    • 2022-12-11
    • 2020-06-13
    • 1970-01-01
    • 2018-02-06
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 2017-10-20
    • 2018-08-29
    相关资源
    最近更新 更多