使用节点中的psql(pg-promise)来承诺循环/ promise.all

你好,我是Promises的新手,并坚持如何等待for循环内的所有承诺,然后去下一个()。 我见过几个promise.all的例子,但我不清楚如何适应他们为我的下面的代码。 它现在转到for循环后的next(),并在for循环完成之前解决。 任何帮助表示赞赏!

我正在使用pg-promise (带有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; } 

我是pg-promise的作者。

下面是关于无效使用Promise.all的一些注意事项。


当使用代表物理资源的基于承诺的接口时,理解所使用的物理上下文是很重要的。 没有它,你就有可能陷入瓶颈,因为物理资源不能像你的通用承诺解决scheme那样扩展。

pg-promise情况下,你的身体环境由两件事组成:

  • 查询要通过Node.js IO进行pipe道传输的string
  • 连接池提供的连接上下文

每个查询请求获取并释放来自连接池的连接,连接池是非常有限的物理资源。 您的默认池大小为10,由底层驱动程序node-postgres 。 虽然你可以把它增加到100,但是这样做会在连接pipe理上造成过载,所以这不是可扩展的。 一个典型的增长是设定为20,这是平均水平。

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

这样的解决scheme根本无法扩展,并且在这里被列为查询执行的反模式: 任务与根/直接查询 。

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

  • 方法任务 ,如果你没有改变数据
  • 方法tx (交易),如果你正在改变数据

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


在“ 按示例学习”教程中有大量示例和事务 示例 。


考虑到你试图获得多行父行,然后多行子行,你应该看看这个问题: 使用PostgreSQL / NodeJS将JOIN表作为结果数组 。

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

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

这个方法在以下问题中得到了更好的考虑: 使用PostgreSQL / NodeJS将JOIN表作为结果数组 。