query - promise-mysql
Use la promesa de procesar el valor de retorno de MySQL en node.js (7)
Esto se puede lograr de manera muy simple, por ejemplo, con bluebird, como pidió:
var Promise = require(''bluebird'');
function getLastRecord(name)
{
return new Promise(function(resolve, reject){
var connection = getMySQL_connection();
var query_str =
"SELECT name, " +
"FROM records " +
"WHERE (name = ?) " +
"LIMIT 1 ";
var query_var = [name];
var query = connection.query(query_str, query_var, function (err, rows, fields) {
//if (err) throw err;
if (err) {
//throw err;
console.log(err);
logger.info(err);
reject(err);
}
else {
resolve(rows);
//console.log(rows);
}
}); //var query = connection.query(query_str, function (err, rows, fields) {
});
}
getLastRecord(''name_record'')
.then(function(rows){
if (rows > 20) {
console.log("action");
}
})
.error(function(e){console.log("Error handler " + e)})
.catch(function(e){console.log("Catch handler " + e)});
Tengo un fondo de Python y actualmente estoy migrando a node.js. Tengo problemas para ajustarme a node.js debido a su naturaleza asíncrona.
Por ejemplo, estoy intentando devolver un valor desde una función MySQL.
function getLastRecord(name)
{
var connection = getMySQL_connection();
var query_str =
"SELECT name, " +
"FROM records " +
"WHERE (name = ?) " +
"LIMIT 1 ";
var query_var = [name];
var query = connection.query(query_str, query_var, function (err, rows, fields) {
//if (err) throw err;
if (err) {
//throw err;
console.log(err);
logger.info(err);
}
else {
//console.log(rows);
return rows;
}
}); //var query = connection.query(query_str, function (err, rows, fields) {
}
var rows = getLastRecord(''name_record'');
console.log(rows);
Después de leer un poco, me doy cuenta de que el código anterior no funciona y debo devolver una promesa debido a la naturaleza asíncrona de node.js. No puedo escribir código node.js como python. ¿Cómo convierto getLastRecord()
para devolver una promesa y cómo manejo el valor devuelto?
De hecho, lo que quiero hacer es algo como esto;
if (getLastRecord() > 20)
{
console.log("action");
}
¿Cómo se puede hacer esto en node.js de forma legible?
Me gustaría ver cómo se pueden implementar las promesas en este caso usando bluebird.
Esto va a estar un poco disperso, perdóname.
Primero, asumiendo que este código utiliza la API del controlador mysql correctamente, aquí hay una forma en que podría ajustarlo para que funcione con una promesa nativa:
function getLastRecord(name)
{
return new Promise(function(resolve, reject) {
// The Promise constructor should catch any errors thrown on
// this tick. Alternately, try/catch and reject(err) on catch.
var connection = getMySQL_connection();
var query_str =
"SELECT name, " +
"FROM records " +
"WHERE (name = ?) " +
"LIMIT 1 ";
var query_var = [name];
connection.query(query_str, query_var, function (err, rows, fields) {
// Call reject on error states,
// call resolve with results
if (err) {
return reject(err);
}
resolve(rows);
});
});
}
getLastRecord(''name_record'').then(function(rows) {
// now you have your rows, you can see if there are <20 of them
}).catch((err) => setImmediate(() => { throw err; })); // Throw async to escape the promise chain
Así que una cosa: todavía tienes devoluciones de llamada. Las devoluciones de llamada son solo funciones que le das a algo para llamar en algún momento en el futuro con argumentos de su elección. Por lo tanto, los argumentos de función en xs.map(fn)
, las funciones (err, result)
que se ven en el nodo y el resultado de la promesa y los controladores de errores son devoluciones de llamada. Esto es algo confundido por las personas que se refieren a un tipo específico de devolución de llamada como "devoluciones de llamada", las de (err, result)
utilizadas en el núcleo del nodo en lo que se denomina "estilo de paso de continuación", a veces llamado "nodebacks" por personas que no Realmente me gustan.
Por ahora, al menos (async / await llegará con el tiempo), estás bastante atascado con las devoluciones de llamada, independientemente de si adoptas promesas o no.
Además, señalaré que las promesas no son inmediatas, obviamente son útiles aquí, ya que todavía tiene una devolución de llamada. Las promesas solo brillan realmente cuando se combinan con Promise.all
y se prometen acumuladores a la Array.prototype.reduce
. Pero a veces brillan, y vale la pena aprender.
He modificado su código para usar las promesas Q (módulo NPM). Supuse que la función ''getLastRecord ()'' que especificó en el fragmento de código anterior funciona correctamente.
Puede consultar el siguiente enlace para obtener el módulo Q
Haga clic aquí: Q documentación
var q = require(''q'');
function getLastRecord(name)
{
var deferred = q.defer(); // Use Q
var connection = getMySQL_connection();
var query_str =
"SELECT name, " +
"FROM records " +
"WHERE (name = ?) " +
"LIMIT 1 ";
var query_var = [name];
var query = connection.query(query_str, query_var, function (err, rows, fields) {
//if (err) throw err;
if (err) {
//throw err;
deferred.reject(err);
}
else {
//console.log(rows);
deferred.resolve(rows);
}
}); //var query = connection.query(query_str, function (err, rows, fields) {
return deferred.promise;
}
// Call the method like this
getLastRecord(''name_record'')
.then(function(rows){
// This function get called, when success
console.log(rows);
},function(error){
// This function get called, when error
console.log(error);
});
No necesita usar promesas, puede usar una función de devolución de llamada, algo así:
function getLastRecord(name, next)
{
var connection = getMySQL_connection();
var query_str =
"SELECT name, " +
"FROM records " +
"LIMIT 1 ";
var query_var = [name];
var query = connection.query(query_str, query_var, function (err, rows, fields) {
//if (err) throw err;
if (err) {
//throw err;
console.log(err);
logger.info(err);
next(err);
}
else {
//console.log(rows);
next(null, rows);
}
}); //var query = connection.query(query_str, function (err, rows, fields) {
}
getLastRecord(''name_record'', function(err, data) {
if(err) {
// handle the error
} else {
// handle your data
}
});
Para responder a su pregunta inicial: ¿Cómo se puede hacer esto en node.js de forma legible?
Existe una biblioteca llamada co
, que le brinda la posibilidad de escribir código asíncrono en un flujo de trabajo síncrono. Sólo eche un vistazo y npm install co
.
El problema al que se enfrenta con frecuencia con este enfoque es que no obtiene Promise
de todas las bibliotecas que le gusta usar. Por lo tanto, puede envolverlo usted mismo (ver la respuesta de @Joshua Holbrook) o buscar un envoltorio (por ejemplo: npm install mysql-promise
)
(Btw: está en la hoja de ruta para que ES7 tenga soporte nativo para este tipo de flujo de trabajo con las palabras clave async
await
, pero aún no está en la lista de características node: node ).
Soy nuevo en Node.js y promete. Estuve buscando por un tiempo algo que satisfaga mis necesidades y esto es lo que terminé usando después de combinar varios ejemplos que encontré. Quería la posibilidad de adquirir conexión por consulta y liberarla justo después de que finalice la consulta ( querySql
), o obtener una conexión del grupo y usarla dentro del alcance de Promise.using, o liberarla cuando me gustaría ( getSqlConnection
). Usando este método, puede realizar varias consultas una tras otra sin anidarlas.
db.js
var mysql = require(''mysql'');
var Promise = require("bluebird");
Promise.promisifyAll(mysql);
Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);
var pool = mysql.createPool({
host: ''my_aws_host'',
port: ''3306'',
user: ''my_user'',
password: ''my_password'',
database: ''db_name''
});
function getSqlConnection() {
return pool.getConnectionAsync().disposer(function (connection) {
console.log("Releasing connection back to pool")
connection.release();
});
}
function querySql (query, params) {
return Promise.using(getSqlConnection(), function (connection) {
console.log("Got connection from pool");
if (typeof params !== ''undefined''){
return connection.queryAsync(query, params);
} else {
return connection.queryAsync(query);
}
});
};
module.exports = {
getSqlConnection : getSqlConnection,
querySql : querySql
};
use_ruta.js
var express = require(''express'');
var router = express.Router();
var dateFormat = require(''dateformat'');
var db = require(''../my_modules/db'');
var getSqlConnection = db.getSqlConnection;
var querySql = db.querySql;
var Promise = require("bluebird");
function retrieveUser(token) {
var userQuery = "select id, email from users where token = ?";
return querySql(userQuery, [token])
.then(function(rows){
if (rows.length == 0) {
return Promise.reject("did not find user");
}
var user = rows[0];
return user;
});
}
router.post(''/'', function (req, res, next) {
Promise.resolve().then(function () {
return retrieveUser(req.body.token);
})
.then(function (user){
email = user.email;
res.status(200).json({ "code": 0, "message": "success", "email": email});
})
.catch(function (err) {
console.error("got error: " + err);
if (err instanceof Error) {
res.status(400).send("General error");
} else {
res.status(200).json({ "code": 1000, "message": err });
}
});
});
module.exports = router;
Usando el paquete promesa-mysql, la lógica sería encadenar promesas usando entonces (función (respuesta) {su código})
y
catch (función (respuesta) {su código}) para detectar errores de los bloques "entonces" que preceden al bloque catch.
Siguiendo esta lógica, pasará los resultados de la consulta en objetos o matrices utilizando el retorno al final del bloque. La devolución ayudará a pasar los resultados de la consulta al siguiente bloque. Luego, el resultado se encontrará en el argumento de la función (aquí está test1). Usando esta lógica, puede encadenar varias consultas de MySql y el código que se requiere para manipular el resultado y hacer lo que quiera.
El objeto de conexión se crea para ser global porque cada objeto y variable creados en cada bloque son solo locales. No olvides que puedes encadenar más bloques "entonces".
var config = {
host : ''host'',
user : ''user'',
password : ''pass'',
database : ''database'',
};
var mysql = require(''promise-mysql'');
var connection;
let thename =""; // which can also be an argument if you embed this code in a function
mysql.createConnection(config
).then(function(conn){
connection = conn;
let test = connection.query(''select name from records WHERE name=? LIMIT 1'',[thename]);
return test;
}).then(function(test1){
console.log("test1"+JSON.stringify(test1)); // result of previous block
var result = connection.query(''select * from users''); // A second query if you want
connection.end();
connection = {};
return result;
}).catch(function(error){
if (connection && connection.end) connection.end();
//logs out the error from the previous block (if there is any issue add a second catch behind this one)
console.log(error);
});