leo-er leo-er - 1 year ago 99
Javascript Question

Replacing callbacks with promises in Node.js

I have a simple node module which connects to a database and has several functions to receive data, for example this function:


var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'password',
database: 'db'

exports.getUsers = function (callback) {
connection.connect(function () {
connection.query('SELECT * FROM Users', function (err, result) {

The module would be called that way from a different node module:


var dbCon = require('./dbConnection.js');

I would like to use promises instead of callbacks in order to return the data.
So far I've read about nested promises in the following thread: Writing Clean Code With Nested Promises, but I couldn't find any solution that is simple enough for this use case.
What would be the correct way to return
using a promise?
I'd like to use the q node module for that.

Answer Source

With bluebird you can use Promise.promisifyAll (and Promise.promisify) to add Promise ready methods to any object.

var Promise = require('bluebird');
// Somewhere around here, the following line is called

exports.getUsersAsync = function () {
    return connection.connectAsync()
        .then(function () {
            return connection.queryAsync('SELECT * FROM Users')

And use like this:



// 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.

Adding disposers

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.
        .disposer(function(connection, promise) { 
            //Disposer is used when Promise.using is finished.

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