web-dev-qa-db-fra.com

Utilisez la promesse pour traiter la valeur de retour MySQL dans node.js

J'ai un arrière-plan python et migre actuellement vers node.js. J'ai du mal à m'adapter à node.js en raison de sa nature asynchrone.

Par exemple, j'essaie de renvoyer une valeur à partir d'une fonction 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);

Après quelques lectures, je réalise que le code ci-dessus ne peut pas fonctionner et que je dois retourner une promesse en raison de la nature asynchrone de node.js. Je ne peux pas écrire de code node.js comme python. Comment convertir getLastRecord() pour renvoyer une promesse et comment gérer la valeur renvoyée?

En fait, ce que je veux faire est quelque chose comme ça;

if (getLastRecord() > 20)
{
    console.log("action");
}

Comment cela peut-il être fait dans node.js de manière lisible? 

Je voudrais voir comment les promesses peuvent être mises en œuvre dans ce cas en utilisant Bluebird.

20
user781486

J'ai modifié votre code pour utiliser les promesses Q (module NPM) . J'ai supposé que votre fonction 'getLastRecord ()' que vous avez spécifiée dans l'extrait ci-dessus fonctionne correctement.

Vous pouvez vous référer au lien suivant pour vous procurer le module Q

Cliquez ici: documentation Q

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);

 });
7
Piyush Sagar

Je suis nouveau sur Node.js et promesses. Je cherchais depuis quelque temps quelque chose qui répondrait à mes besoins et c’est ce que j’ai utilisé après avoir combiné plusieurs exemples que j’ai trouvés. Je souhaitais pouvoir acquérir une connexion par requête et la libérer juste après la fin de la requête (querySql), ou obtenir une connexion d'un pool et l'utiliser dans la portée de Promise.using, ou la libérer à tout moment (getSqlConnection) . En utilisant cette méthode, vous pouvez concaténer plusieurs requêtes les unes après les autres sans les imbriquer.

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
};

usage_route.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;
6
MikeL

Pour répondre à votre question initiale: comment cela peut-il être fait dans node.js de manière lisible?

Il existe une bibliothèque appelée co , qui vous donne la possibilité d'écrire du code async dans un flux de travail synchrone. Il suffit de regarder et npm install co.

Le problème que vous rencontrez très souvent avec cette approche est que vous ne récupérez pas Promise de toutes les bibliothèques que vous aimez utiliser. Donc, vous devez soit l’envelopper vous-même (voir la réponse de @Joshua Holbrook), soit rechercher un emballage (par exemple: npm install mysql-promise)

(Btw: il est sur la feuille de route pour ES7 d'avoir un support natif pour ce type de workflow avec les mots-clés asyncawait, mais ce n'est pas encore dans le noeud: liste des fonctionnalités du noeud .)

3
CFrei

Vous n'avez pas besoin d'utiliser des promesses, vous pouvez utiliser une fonction de rappel, quelque chose comme ça:

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

   }
});
3
Jordi Ruiz

Ceci peut être réalisé très simplement, par exemple avec bluebird, comme vous l'avez demandé:

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)});
2
Andrej Burcev

En utilisant le paquet promise-mysql la logique serait de chaîner les promesses en utilisant ensuite (fonction (réponse) {votre code})

et 

catch (fonction (réponse) {votre code}) pour intercepter les erreurs des blocs "then" précédant le bloc catch.

En suivant cette logique, vous passerez les résultats de la requête dans des objets ou des tableaux à l'aide de return à la fin du bloc. Le retour aidera à transmettre les résultats de la requête au bloc suivant. Ensuite, le résultat sera trouvé dans l'argument de la fonction (ici test1). En utilisant cette logique, vous pouvez chaîner plusieurs requêtes MySql et le code requis pour manipuler le résultat et faire ce que vous voulez. 

l'objet Connection est créé pour être global, car chaque objet et toute variable créés dans chaque bloc sont uniquement locaux. N'oubliez pas que vous pouvez enchaîner plus de "alors" blocs.

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);
  });
1