Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping Node.js callbacks in Promises using Bluebird

How do I wrap a Node.js callback using a Promise in Bluebird? This is what I came up with, but wanted to know if there is a better way:

return new Promise(function(onFulfilled, onRejected) {
    nodeCall(function(err, res) {
            if (err) {
                onRejected(err);
            }
            onFulfilled(res);
        });
});

Is there a cleaner way to do this if only an error needs to be returned back?

Edit I tried to use Promise.promisifyAll(), but the result is not being propagated to the then clause. My specific example is shown below. I am using two libraries: a) sequelize, which returns promises, b) supertest (used for testing http requests), which uses node style callbacks. Here's the code without using promisifyAll. It calls sequelize to initialize the database and then makes an HTTP request to create the order. Bosth console.log statements are printed correctly:

var request = require('supertest');

describe('Test', function() {
    before(function(done) {
        // Sync the database
        sequelize.sync(
        ).then(function() {
            console.log('Create an order');
            request(app)
                .post('/orders')
                .send({
                    customer: 'John Smith'
                })
                .end(function(err, res) {
                    console.log('order:', res.body);
                    done();
                });
        });
    });

    ...
});

Now I try to use promisifyAll, so that I can chain the calls with then:

var request = require('supertest');
Promise.promisifyAll(request.prototype);

describe('Test', function() {
    before(function(done) {
        // Sync the database
        sequelize.sync(
        ).then(function() {
            console.log('Create an order');
            request(app)
                .post('/orders')
                .send({
                    customer: 'John Smith'
                })
                .end();
        }).then(function(res) {
            console.log('order:', res.body);
            done();
        });
    });

    ...
});

When I get to the second console.log the res argument is undefined.

Create an order
Possibly unhandled TypeError: Cannot read property 'body' of undefined

What am I doing wrong?

like image 605
Naresh Avatar asked Mar 31 '14 12:03

Naresh


1 Answers

You are not calling the promise returning version and not returning it either.

Try this:

   // Add a return statement so the promise is chained
   return request(app)
            .post('/orders')
            .send({
                customer: 'John Smith'
            })
            // Call the promise returning version of .end()
            .endAsync(); 
like image 59
Esailija Avatar answered Oct 20 '22 11:10

Esailija