使用节点中的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表作为结果数组 。