Node.js에서 콜백을 프라 미스로 대체
데이터베이스에 연결하고 데이터를 수신하는 여러 기능이있는 간단한 노드 모듈이 있습니다 (예 :이 기능).
dbConnection.js :
import mysql from 'mysql';
const connection = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'password',
database: 'db'
});
export default {
getUsers(callback) {
connection.connect(() => {
connection.query('SELECT * FROM Users', (err, result) => {
if (!err){
callback(result);
}
});
});
}
};
모듈은 다른 노드 모듈에서 다음과 같이 호출됩니다.
app.js :
import dbCon from './dbConnection.js';
dbCon.getUsers(console.log);
데이터를 반환하기 위해 콜백 대신 promise를 사용하고 싶습니다. 지금까지 다음 스레드에서 중첩 된 약속에 대해 읽었습니다 : Writing Clean Code With Nested Promises ,하지만이 사용 사례에 대해 충분히 간단한 솔루션을 찾을 수 없습니다. result
약속을 사용하여 반환하는 올바른 방법은 무엇입니까 ?
Promise
수업 사용
Promise 사용을위한 좋은 시작점을 제공하는 MDN의 Promise 문서 를 살펴 보는 것이 좋습니다 . 또는 온라인에서 사용할 수있는 많은 자습서가 있다고 확신합니다. :)
참고 : 최신 브라우저는 이미 ECMAScript 6 Promises 사양을 지원하며 (위에 링크 된 MDN 문서 참조) 타사 라이브러리없이 기본 구현을 사용한다고 가정합니다.
실제 예는 ...
기본 원리는 다음과 같습니다.
- API가 호출되었습니다.
- 새로운 Promise 객체를 생성합니다.이 객체는 생성자 매개 변수로 단일 함수를 사용합니다.
- 귀하의 제공 기능이 기본이되는 구현에 의해 호출되며, 함수는 두 가지 기능을 부여 -
resolve
과reject
- 논리를 수행 한 후에는 이들 중 하나를 호출하여 약속을 채우거나 오류로 거부합니다.
이것은 많은 것처럼 보일 수 있으므로 여기에 실제 예가 있습니다.
exports.getUsers = function getUsers () {
// Return the Promise right away, unless you really need to
// do something before you create a new Promise, but usually
// this can go into the function below
return new Promise((resolve, reject) => {
// reject and resolve are functions provided by the Promise
// implementation. Call only one of them.
// Do your logic here - you can do WTF you want.:)
connection.query('SELECT * FROM Users', (err, result) => {
// PS. Fail fast! Handle errors first, then move to the
// important stuff (that's a good practice at least)
if (err) {
// Reject the Promise with an error
return reject(err)
}
// Resolve (or fulfill) the promise with data
return resolve(result)
})
})
}
// Usage:
exports.getUsers() // Returns a Promise!
.then(users => {
// Do stuff with users
})
.catch(err => {
// handle errors
})
async / await 언어 기능 사용 (Node.js> = 7.6)
Node.js 7.6에서 v8 JavaScript 컴파일러는 async / await 지원 으로 업그레이드되었습니다 . 이제 함수를로 선언 할 수 있습니다. async
즉 Promise
, 비동기 함수가 실행을 완료하면 해결되는 a 를 자동으로 반환합니다 . 이 함수 내에서 await
키워드를 사용하여 다른 Promise가 해결 될 때까지 기다릴 수 있습니다 .
다음은 예입니다.
exports.getUsers = async function getUsers() {
// We are in an async function - this will return Promise
// no matter what.
// We can interact with other functions which return a
// Promise very easily:
const result = await connection.query('select * from users')
// Interacting with callback-based APIs is a bit more
// complicated but still very easy:
const result2 = await new Promise((resolve, reject) => {
connection.query('select * from users', (err, res) => {
return void err ? reject(err) : resolve(res)
})
})
// Returning a value will cause the promise to be resolved
// with that value
return result
}
함께 블루 버드 당신이 사용할 수있는 Promise.promisifyAll
(그리고 Promise.promisify
모든 개체에 약속 준비 방법을 추가).
var Promise = require('bluebird');
// Somewhere around here, the following line is called
Promise.promisifyAll(connection);
exports.getUsersAsync = function () {
return connection.connectAsync()
.then(function () {
return connection.queryAsync('SELECT * FROM Users')
});
};
다음과 같이 사용하십시오.
getUsersAsync().then(console.log);
또는
// Spread because MySQL queries actually return two resulting arguments,
// which Bluebird resolves as an array.
getUsersAsync().spread(function(rows, fields) {
// Do whatever you want with either rows or fields.
});
처리기 추가
Bluebird supports a lot of features, one of them is disposers, it allows you to safely dispose of a connection after it ended with the help of Promise.using
and Promise.prototype.disposer
. Here's an example from my app:
function getConnection(host, user, password, port) {
// connection was already promisified at this point
// The object literal syntax is ES6, it's the equivalent of
// {host: host, user: user, ... }
var connection = mysql.createConnection({host, user, password, port});
return connection.connectAsync()
// connect callback doesn't have arguments. return connection.
.return(connection)
.disposer(function(connection, promise) {
//Disposer is used when Promise.using is finished.
connection.end();
});
}
Then use it like this:
exports.getUsersAsync = function () {
return Promise.using(getConnection()).then(function (connection) {
return connection.queryAsync('SELECT * FROM Users')
});
};
This will automatically end the connection once the promise resolves with the value (or rejects with an Error
).
Node.js version 8.0.0+:
You don't have to use bluebird to promisify the node API methods anymore. Because, from version 8+ you can use native util.promisify:
const util = require('util');
const connectAsync = util.promisify(connection.connectAsync);
const queryAsync = util.promisify(connection.queryAsync);
exports.getUsersAsync = function () {
return connectAsync()
.then(function () {
return queryAsync('SELECT * FROM Users')
});
};
Now, don't have to use any 3rd party lib to do the promisify.
Assuming your database adapter API doesn't output Promises
itself you can do something like:
exports.getUsers = function () {
var promise;
promise = new Promise();
connection.connect(function () {
connection.query('SELECT * FROM Users', function (err, result) {
if(!err){
promise.resolve(result);
} else {
promise.reject(err);
}
});
});
return promise.promise();
};
If the database API does support Promises
you could do something like: (here you see the power of Promises, your callback fluff pretty much disappears)
exports.getUsers = function () {
return connection.connect().then(function () {
return connection.query('SELECT * FROM Users');
});
};
Using .then()
to return a new (nested) promise.
Call with:
module.getUsers().done(function (result) { /* your code here */ });
I used a mockup API for my Promises, your API might be different. If you show me your API I can tailor it.
When setting up a promise you take two parameters, resolve
and reject
. In the case of success, call resolve
with the result, in the case of failure call reject
with the error.
Then you can write:
getUsers().then(callback)
callback
will be called with the result of the promise returned from getUsers
, i.e. result
Using the Q library for example:
function getUsers(param){
var d = Q.defer();
connection.connect(function () {
connection.query('SELECT * FROM Users', function (err, result) {
if(!err){
d.resolve(result);
}
});
});
return d.promise;
}
2019:
Use that native module const {promisify} = require('util');
to conver plain old callback pattern to promise pattern so you can get benfit from async/await
code
const {promisify} = require('util');
const glob = promisify(require('glob'));
app.get('/', async function (req, res) {
var glob = promisify(require('glob'));
const files = await glob('src/**/*-spec.js');
res.render('mocha-template-test', {files});
});
Below code works only for node -v > 8.x
I use this Promisified MySQL middleware for Node.js
read this article Create a MySQL Database Middleware with Node.js 8 and Async/Await
database.js
var mysql = require('mysql');
// node -v must > 8.x
var util = require('util');
// !!!!! for node version < 8.x only !!!!!
// npm install util.promisify
//require('util.promisify').shim();
// -v < 8.x has problem with async await so upgrade -v to v9.6.1 for this to work.
// connection pool https://github.com/mysqljs/mysql [1]
var pool = mysql.createPool({
connectionLimit : process.env.mysql_connection_pool_Limit, // default:10
host : process.env.mysql_host,
user : process.env.mysql_user,
password : process.env.mysql_password,
database : process.env.mysql_database
})
// Ping database to check for common exception errors.
pool.getConnection((err, connection) => {
if (err) {
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
console.error('Database connection was closed.')
}
if (err.code === 'ER_CON_COUNT_ERROR') {
console.error('Database has too many connections.')
}
if (err.code === 'ECONNREFUSED') {
console.error('Database connection was refused.')
}
}
if (connection) connection.release()
return
})
// Promisify for Node.js async/await.
pool.query = util.promisify(pool.query)
module.exports = pool
You must upgrade node -v > 8.x
you must use async function to be able to use await.
example:
var pool = require('./database')
// node -v must > 8.x, --> async / await
router.get('/:template', async function(req, res, next)
{
...
try {
var _sql_rest_url = 'SELECT * FROM arcgis_viewer.rest_url WHERE id='+ _url_id;
var rows = await pool.query(_sql_rest_url)
_url = rows[0].rest_url // first record, property name is 'rest_url'
if (_center_lat == null) {_center_lat = rows[0].center_lat }
if (_center_long == null) {_center_long= rows[0].center_long }
if (_center_zoom == null) {_center_zoom= rows[0].center_zoom }
_place = rows[0].place
} catch(err) {
throw new Error(err)
}
참고URL : https://stackoverflow.com/questions/28432401/replacing-callbacks-with-promises-in-node-js
'Programing' 카테고리의 다른 글
Calendar.getInstance (TimeZone.getTimeZone ( "UTC"))가 UTC 시간을 반환하지 않습니다. (0) | 2020.09.05 |
---|---|
Linux Bash에서 이중 앰퍼샌드 (&&)와 세미콜론 (;)의 차이점은 무엇입니까? (0) | 2020.09.05 |
유형 및 유형 별칭 간의 Elm의 차이점은 무엇입니까? (0) | 2020.09.05 |
플렉스 박스 요소 중앙 및 오른쪽 정렬 (0) | 2020.09.05 |
하드 랩과 소프트 랩의 차이점은 무엇입니까? (0) | 2020.09.05 |