ForEach循环内asynchronous/等待节点Postgres查询

编辑:我使用节点v8.0.0

我刚刚开始学习如何使用node-postgres访问SQL数据库,并且在访问多个数据库以便以可工作的格式收集数据时遇到了一些问题,特别是在forEach循环中执行多个查询时。 经过几次尝试,我试着asynchronous/等待,但我得到以下错误:

await client.connect() ^^^^^^ SyntaxError: Unexpected identifier 

当我尝试使用一个池或顺序调用.query,我会得到的东西沿线

 1 [] could not connect to postgres Error: Connection terminated 

这里是我的代码的缩写版本:

 const { Client } = require('pg'); const moment = require('moment'); const _ = require('lodash'); const turf = require('@turf/turf'); const connString = // connection string var collected = [] const CID = 300 const snaptimes = // array of times var counter=0; const client = new Client(connString); function createArray(i,j) { // return array of i arrays of length j } await client.connect() snaptimes.forEach(function(snaptime){ var info = {}; // an object of objects // get information at given snaptime from database 1 const query1 = // parametrized query selecting two columns from database 1 const result1 = await client.query(query1, [CID,snaptime]); var x = result1.rows; for (var i = 0; i < x.length; i++) { // store data from database 1 into info // each row is an object with two fields } // line up subjects on the hole const query2 = // parametrized query grabbing JSON string from database 2 const result2 = await client.query(query2, [CID,snaptime]); const raw = result2.rows[0].JSON_col; const line = createArray(19,0); // an array of 19 empty arrays for (var i = 0; i < raw.length; i++) { // parse JSON object and record data into line } // begin to collect data var n = 0; var g = 0; // walk down the line for (var i = 18; i > 0; i--) { // if no subjects are found at spot i, do nothing, except maybe update g if ((line[i] === undefined || line[i].length == 0) && g == 0){ g = i; } else if (line[i] !== undefined && line[i].length != 0) { // collect data for each subject if subjects are found line[i].forEach(function(subject){ const query 3 = // parametrized query grabbing data for each subject const result3 = await client.query(query3,[CID,subject,snaptime]); x = result3.rows; const y = moment(x[0].end_time).diff(moment(snaptime),'minutes'); var yhat = 0; // the summation over info depends on g if (g===0){ for (var j = i; j <= 18; j++){ yhat = moment.duration(info[j].field1).add(yhat,'m').asMinutes(); } } else { for (var j = i; j <= 18; j++){ if (i<j && j<g+1) { yhat = moment.duration(info[j].field2).add(yhat,'m').asMinutes(); } else { yhat = moment.duration(info[j].field1).add(yhat,'m').asMinutes(); } } } collected.push([y,yhat,n,i]); }); } n+=line[i].length; g=0; } // really rough work-around I once used for printing results after a forEach of queries counter++; if (counter===snaptimes.length){ console.log(counter); console.log(collected); client.end(); } }); 

问题是由您的forEachcallback不是async造成的:

 snaptimes.forEach(function(snaptime){ 

应该:

 snaptimes.forEach(async function (snaptime) { 

为了await被认可。

请记住,一个async函数会立即返回,并返回一个承诺,最终通过async函数的return语句来parsing(或者被async函数中引发的未捕获exception所拒绝)。

但也要确保你的Node版本支持async / await

  • 由于节点7.6可以使用没有--harmony标志。
  • 在7.6之前的节点7.x中,你必须使用--harmony标志。
  • 它在7.0之前的Node中不可用。

请参阅: http : //node.green/#ES2017-features-async-functions

另请注意, 只能在使用async关键字声明的函数内部使用await 。 如果你想在脚本或模块的顶层使用它,那么你需要将它包装在一个立即调用的函数expression式中:

 // cannot use await here (async () => { // can use await here })(); // cannot use await here 

例:

 const f = () => new Promise(r => setTimeout(() => r('x'), 500)); let x = await f(); console.log(x); 

打印:

 $ node t1.js /home/rsp/node/test/prom-async/t1.js:3 let x = await f(); ^ SyntaxError: Unexpected identifier 

但是这个:

 const f = () => new Promise(r => setTimeout(() => r('x'), 500)); (async () => { let x = await f(); console.log(x); })(); 

打印:

 $ node t2.js x 

延期0.5秒后,如预期。

在不支持async的Node版本上, await第一个(不正确)的例子将会打印:

 $ ~/opt/node-v6.7.0/bin/node t1.js /home/rsp/node/test/prom-async/t1.js:3 let x = await f(); ^ SyntaxError: Unexpected identifier 

而第二个(正确的)例子将会打印一个不同的错误:

 $ ~/opt/node-v6.7.0/bin/node t2.js /home/rsp/node/test/prom-async/t2.js:3 (async () => { ^ SyntaxError: Unexpected token ( 

这很有用,因为不支持async / await Node版本不会给你一个像“async / await not supported”之类的有意义的错误,不幸的是,

确保你应该在外面使用async块:

 async function() { return await Promise.resolve('') } 

它在节点7.6.0后默认支持。 在7.6.0之前,你应该使用--harmony选项来工作。

node -v首先检查你的版本。

首先,你还不够了解asynchronous等待。 别担心,其实很简单; 但你需要阅读文档才能使用这些东西。

更重要的是,你的代码的问题是,你只能在async函数内部await ; 你在做任何function之外的事情。

首先,这里是最接近你写的代码的解决scheme:

 const { Client } = require('pg'); const moment = require('moment'); const _ = require('lodash'); const turf = require('@turf/turf'); const connString = // connection string var collected = [] const CID = 300 const snaptimes = // array of times var counter=0; const client = new Client(connString); function createArray(i,j) { // return array of i arrays of length j } async function processSnaptime (snaptime) { var info = {}; // an object of objects // get information at given snaptime from database 1 const query1 = // parametrized query selecting two columns from database 1 const result1 = await client.query(query1, [CID,snaptime]); var x = result1.rows; for (var i = 0; i < x.length; i++) { // store data from database 1 into info // each row is an object with two fields } // line up subjects on the hole const query2 = // parametrized query grabbing JSON string from database 2 const result2 = await client.query(query2, [CID,snaptime]); const raw = result2.rows[0].JSON_col; const line = createArray(19,0); // an array of 19 empty arrays for (var i = 0; i < raw.length; i++) { // parse JSON object and record data into line } // begin to collect data var n = 0; var g = 0; // walk down the line for (var i = 18; i > 0; i--) { // if no subjects are found at spot i, do nothing, except maybe update g if ((line[i] === undefined || line[i].length == 0) && g == 0){ g = i; } else if (line[i] !== undefined && line[i].length != 0) { // collect data for each subject if subjects are found line[i].forEach(function(subject){ const query 3 = // parametrized query grabbing data for each subject const result3 = await client.query(query3,[CID,subject,snaptime]); x = result3.rows; const y = moment(x[0].end_time).diff(moment(snaptime),'minutes'); var yhat = 0; // the summation over info depends on g if (g===0){ for (var j = i; j <= 18; j++){ yhat = moment.duration(info[j].field1).add(yhat,'m').asMinutes(); } } else { for (var j = i; j <= 18; j++){ if (i<j && j<g+1) { yhat = moment.duration(info[j].field2).add(yhat,'m').asMinutes(); } else { yhat = moment.duration(info[j].field1).add(yhat,'m').asMinutes(); } } } collected.push([y,yhat,n,i]); }); } n+=line[i].length; g=0; } // really rough work-around I once used for printing results after a forEach of queries counter++; if (counter===snaptimes.length){ console.log(counter); console.log(collected); } } async function run () { for (let snaptime of snaptimes) { await processSnaptime(snaptime); } } /* to run all of them concurrently: function run () { let procs = []; for (let snaptime of snaptimes) { procs.push(processSnaptime(snaptime)); } return Promise.all(procs); } */ client.connect().then(run).then(() => client.end()); 

client.connect返回一个承诺, then我使用它来调用run一旦解决。 当部分结束时,可以安全地调用client.end()

run是一个async函数,因此它可以使用await使代码更具可读性。 processSnaptime

当然,我实际上不能运行你的代码,所以我只希望我没有犯任何错误。