使用promise在node.js中处理MySQL返回值

use*_*486 25 mysql asynchronous node.js promise node-mysql

我有一个python背景,目前正在迁移到node.js. 由于其异步性质,我有问题调整到node.js.

例如,我试图从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);
Run Code Online (Sandbox Code Playgroud)

经过一些阅读,我意识到上面的代码无法工作,我需要返回一个由于node.js异步性质的承诺.我不能像python一样编写node.js代码.如何转换getLastRecord()为返回承诺以及如何处理返回的值?

事实上,我想要做的就是这样;

if (getLastRecord() > 20)
{
    console.log("action");
}
Run Code Online (Sandbox Code Playgroud)

如何以可读的方式在node.js中完成?

我想看看在这种情况下如何使用bluebird实现promises.

Jos*_*ook 46

这会有点分散,请原谅我.

首先,假设此代码正确使用了mysql驱动程序API,这里有一种方法可以将其包装为使用本机承诺:

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
Run Code Online (Sandbox Code Playgroud)

所以有一点:你还有回调.回调函数只是函数,您可以通过其选择的参数在将来某个时候调用某些函数.所以函数参数xs.map(fn),(err, result)节点中看到的函数以及promise结果和错误处理程序都是回调函数.这有点让人感到困惑的是人们将特定类型的回调称为"回调",(err, result)在节点核心中使用的是所谓的"延续传递风格",有时被不喜欢它们的人称为"节点回调".

现在,至少(async/await最终会到来),无论你是否采用承诺,你几乎都会遇到回调问题.

此外,我会注意到承诺不是立即的,显然在这里很有帮助,因为你仍然有回调.承诺只有在你将它们与Promise.all累积器结合起来时才能真正发挥作用Array.prototype.reduce.但他们有时会亮的,他们值得我们学习.

  • 顺便说一句:可以避免“try..catch”块,因为在“new Promise”函数中,如果没有“catch”,“throw”将自动调用“reject(err)”。(至少对于函数的同步部分而言。) (2认同)

Piy*_*gar 8

我已修改您的代码以使用Q(NPM模块)承诺.我假设您在上面的代码段中指定的'getLastRecord()'函数正常工作.

您可以参考以下链接来获取Q模块

点击这里: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);

 });
Run Code Online (Sandbox Code Playgroud)


Mik*_*keL 7

我是Node.js和承诺的新手.我正在寻找一些能够满足我需求的东西,这是我在结合我找到的几个例子之后最终使用的.我希望能够获取每个查询的连接并在查询完成后立即释放(querySql),或者从池中获取连接并在Promise.using范围内使用它,或者在我想要它时释放它(getSqlConnection).使用此方法,您可以一个接一个地连接多个查询而不嵌套它们.

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
};
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)


Dil*_*ett 5

我对节点还是有点陌生​​,所以也许我错过了一些让我知道它是如何工作的东西。触发异步节点不会只是将其强加给您,因此您必须提前考虑并计划。

const mysql = require('mysql');
const db = mysql.createConnection({
          host: 'localhost', 
          user: 'user', password: 'password', 
          database: 'database',
      });
      db.connect((err) => {
          // you should probably add reject instead of throwing error
          // reject(new Error()); 
          if(err){throw err;}
          console.log('Mysql: Connected');
      });
      db.promise = (sql) => {
          return new Promise((resolve, reject) => {
              db.query(sql, (err, result) => {
                if(err){reject(new Error());}
                else{resolve(result);}
              });
          });
      };
Run Code Online (Sandbox Code Playgroud)

在这里,我像平常一样使用 mysql 模块,但我创建了一个新函数来提前处理 Promise,将其添加到 db const 中。(您在很多节点示例中将其视为“连接”。

现在让我们使用 Promise 调用 mysql 查询。

      db.promise("SELECT * FROM users WHERE username='john doe' LIMIT 1;")
      .then((result)=>{
          console.log(result);
      }).catch((err)=>{
          console.log(err);
      });
Run Code Online (Sandbox Code Playgroud)

我发现当您需要基于第一个查询执行第二个查询时,这很有用。

      db.promise("SELECT * FROM users WHERE username='john doe' LIMIT 1;")
      .then((result)=>{
          console.log(result);
          var sql = "SELECT * FROM friends WHERE username='";
              sql = result[0];
              sql = "';"
          return db.promise(sql);
      }).then((result)=>{
          console.log(result);
      }).catch((err)=>{
          console.log(err);
      });
Run Code Online (Sandbox Code Playgroud)

您实际上应该使用 mysql 变量,但这至少应该为您提供一个在 mysql 模块中使用 Promise 的示例。

此外,通过上述操作,您仍然可以在这些承诺范围内随时继续以正常方式使用 db.query,它们就像正常一样工作。

希望这对死亡三角有所帮助。