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

我有一个python背景,目前正在迁移到node.js. 由于其asynchronous性质,我有调整到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); 

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

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

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

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

我想看看在这种情况下如何使用蓝鸟实现承诺。

这会有点分散,原谅我。

首先,假设这段代码正确地使用了mysql驱动程序的API,下面是一个方法,可以把它包装到一个本地的promise中:

 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 

所以有一件事:你仍然有callback。 callback函数就是你在将来某个时候用某个参数来调用的东西。 所以xs.map(fn)的函数参数,节点中看到的(err, result)函数以及promise结果和error handling函数都是callback函数。 有些人把某种特定的callback称为“callback” (err, result) ,这种callback在节点核心中被称为“持续传递风格”,有时也被称为“nodeback”真的很喜欢他们。

现在,至less(asynchronous/等待最终会到来),不pipe你是否采用承诺,你都会遇到callback。

另外,我会注意到,承诺并不是立即,在这里显然是有帮助的,因为你仍然有一个callback。 当Promise.allPromise.all结合并承诺累积Promise.all ,promise只会真的发光,而Array.prototype.reduce 。 但是他们有时会闪耀,而且值得学习。

我已经修改你的代码来使用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); }); 

你不需要使用promise,你可以使用一个callback函数,就像这样:

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

回答你的第一个问题:如何以可读的方式在node.js中完成?

有一个名为co的库,它使您可以在同步工作stream中编写asynchronous代码。 只要看看npm install co

你经常用这种方法面对的问题是,你没有从你喜欢使用的所有库中得到Promise 。 所以你要么自己换行(参见@Joshua Holbrook的答案),要么寻找一个包装器(例如: npm install mysql-promise

(顺便说一句:它的ES7的路线图,以支持这种types的工作stream,关键字async await ,但async没有在节点: 节点function列表 。)

我是nodejs和promisses的新手。 我正在寻找一些能满足我需求的东西,这是我结合我发现的几个实践后最终使用的东西。 我希望能够获取每个查询的连接,并在查询完成后立即释放它( querySql ),或者从池中获取连接,并在Promise中使用它。使用范围或每当我想要它时释放它( 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 }; 

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; 

这可以很简单地实现,例如蓝鸟,如你所问:

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