简体   繁体   中英

How we can use promises in node js?

As in asynchronous programming we used to callbacks and promises. Here I am stuck in a problem that may be used to promises. I google it a lot but there is nothing found that solved my problem.

Here My code that I am doing to send push notification in android device.

router.post('/check-notifications', function(req, res, next) {

    var user_id = req.body.user_id;

    var response = {};
    var gcm = require('push-notify').gcm({

        apiKey: gcm_apiKey,
        retries: 0
    });

    connection.query('select device_id from devices where user_id = '+ user_id, function (err, result) {
        if ( result.length ) {

            for (var i = 0; i < result.length; i++) {

                console.log(i + 'before notify');
                gcm.send({

                    registrationId: result[i]['device_id'],
                    data: result[0]
                });

                console.log(i + 'before transmitted');
                gcm.on('transmitted', function (result, message, registrationId) {
                    console.log('transmitted');
                });

                gcm.on('transmissionError', function (error, message, registrationId) {
                    console.log(message);
                });

                console.log(i + 'after notify');

            }
        }           
    });

    response['success'] = true;
    response['msg'] = 'sent successfully';
    res.json(response);
}); 

Output :

0before notify
0before transmitted
0after notify
1before notify
1before transmitted
1after notify
transmitted
transmitted
transmitted
transmitted

And I think It should be like this.

0before notify
0before transmitted
transmitted
0after notify
1before notify
1before transmitted
transmitted
1after notify

You can use async.mapSeries method for chaining notifications. Replace for loop to:

async.mapSeries(result, function(item, callback) {
    gcm.send({
        registrationId: item['device_id'],
        data: data
    });
    gcm.on('transmitted', function(result, message, registrationId) {
        console.log('transmitted');
        callback(null, message, registrationId);
    });

    gcm.on('transmissionError', function(error, message, registrationId) {
        callback(error, message, registrationId);
    });
}, function (err, results) {
    if (err) throw err;
    response['success'] = true;
    response['msg'] = 'sent successfully';
    res.json(response);
})

I recommend using Bluebird JS for Promise flow-control.

var Promise = require('bluebird'); // Require bluebird, and call it 'Promise', the code below is version 3.x syntax

var connection = {'query': '???'}; // assuming `connection` is already defined somewhere else
var gcm_apiKey = '???'; // assuming `gcm_apiKey` is already defined

router.post('/check-notifications', function (req, res, next) {

    var user_id = req.body.user_id;

    var gcm = require('push-notify').gcm({
        apiKey: gcm_apiKey,
        retries: 0
    });

    // assuming `connection` is already defined somewhere else
    // Make an async version of connection.query
    connection.queryAsync = Promise.promisify(connection.query);

    connection.queryAsync('select device_id from devices where user_id = ' + user_id)
        // Bluebird's Promise.map would execute the following block once per result, asynchronously.
        // The sequence of who runs first and who completes first is undefined
        .map(function (result, i) {
            // the `result` argument here is `result[i]` of the original code, since we're in the map context

            // Here we have to create a promise to consume events
            return new Promise(function (resolve, reject) {

                console.log(i + 'before notify');
                gcm.send({
                    registrationId: result['device_id'],
                    data: result // original code is written as result[0], which I don't quite understand. Always sending the first result?
                });

                // This does not make sense console logging here, as it is not actually 'before transmitted'
                // It's just binding onto the event
                // console.log(i + 'before transmitted'); 
                gcm.on('transmitted', function (result, message, registrationId) {
                    // Check registrationId
                    if (registrationId === result['device_id']) {
                      console.log('transmitted');
                      resolve(result); // use 'result' as the Promise's resolved value 
                    }
                });

                gcm.on('transmissionError', function (error, message, registrationId) {
                    // Check registrationId
                    if (registrationId === result['device_id']) {
                      console.log(message);
                      reject(message); // reject errors and send the message as the promise's reject reason
                    }
                });

                // Technically, you should log it as "after event binding"
                console.log(i + 'after notify');

            });
        }).then(function (results) {
            // `results` should contain all the result from the 'transmitted' event

            var response = {};
            response['success'] = true;
            response['msg'] = 'sent successfully';
            res.json(response);
        });

});

Note: The is actually more or less doable without any libraries but with native Promises, but the syntax would be more cluttering.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM