Las consultas de base de datos asíncronas con PostgreSQL en el nodo no funcionan

Al utilizar Node.js y el módulo node-postgres para comunicarse con una base de datos, estoy intentando escribir una función que acepte una serie de consultas y devoluciones de llamadas y las ejecute todas de forma asíncrona utilizando la misma conexión de base de datos. La función acepta una matriz bidimensional y llamándola así:

perform_queries_async([ ['SELECT COUNT(id) as count FROM ideas', function(result) { console.log("FUNCTION 1"); }], ["INSERT INTO ideas (name) VALUES ('test')", function(result) { console.log("FUNCTION 2"); }] ]); 

Y la función itera sobre la matriz, creando una consulta para cada sub-matriz, así:

 function perform_queries_async(queries) { var client = new pg.Client(process.env.DATABASE_URL); for(var i=0; i<queries.length; i++) { var q = queries[i]; client.query(q[0], function(err, result) { if(err) { console.log(err); } else { q[1](result); } }); } client.on('drain', function() { console.log("drained"); client.end(); }); client.connect(); } 

Cuando ejecuté el código anterior, esperaba ver una salida como esta:

 FUNCTION 1 FUNCTION 2 drained 

Sin embargo, la salida extrañamente se ve así:

 FUNCTION 2 drained FUNCTION 2 

No solo se llama a la segunda función para ambas solicitudes, también parece que se está llamando al código de drenaje antes de que la cola de consultas del cliente termine de ejecutarse … sin embargo, la segunda consulta sigue funcionando perfectamente bien aunque el client.end() código supuestamente mató al cliente una vez que se llama al evento.

Llevo horas arrancándome el pelo. Intenté codificar en mi matriz de muestra (eliminando así el bucle for), y mi código funcionó como se esperaba, lo que me lleva a creer que hay un problema con mi bucle que no estoy viendo.

Cualquier idea sobre por qué esto podría estar sucediendo sería muy apreciada.

La forma más sencilla de capturar correctamente el valor de la variable q en un cierre en JavaScript moderno es usar forEach :

 queries.forEach(function(q) { client.query(q[0], function(err, result) { if(err) { console.log(err); } else { q[1](result); } }); }); 

Si no captura el valor, su código refleja el último valor que tuvo q , como la función de callback ejecutada más adelante, en el contexto de la función que lo contiene.

forEach , al usar una función de callback, aísla y captura el valor de q para que se pueda evaluar adecuadamente mediante la callback interna.

Una víctima del famoso cierre de Javascript / loopcha. Ver mis (y otras) respuestas aquí:

Estoy intentando abrir 10 conexiones websocket con nodejs, pero de alguna manera mi bucle no funciona

Básicamente, en el momento en que se ejecuta la callback, q se establece en el último elemento de la matriz de entrada. La forma de evitarlo es generar dinámicamente el cierre.

Será bueno ejecutar esto utilizando el módulo asíncrono. Te ayudará a reutilizar el código también. y hará que el código sea más legible. Me encanta la función automática proporcionada por el módulo asíncrono Ref: https://github.com/caolan/async