简体   繁体   中英

Node.js : multiple callbacks from one function

I've run into a problem in my application's code and I would like to know the best way to handle it: I have a function that applies 5 values on callback and I would like to know the best way to use it.

Here is my function code :

var someFunc = function(callback) {
var http = require('http');
var id;
var url = 'http://somesite.com/json';


// First request to get an array of 5 elements
http.get(url, function(res) {
    var body = '';

    res.on('data', function(chunk) {
        body += chunk;
    });

    res.on('end', function() {
        var jsonResult = JSON.parse(body);
// 5 requests with a value from each of the 5 elements
        for (var i=0;i<5;i++)
        {
            (function(idx) {
                gameId = jsonResult.gameList[idx].id;
                url = 'http://somesite.com' + id + '/token';
                http.get(url, function(res) {
                    var body = '';

                    res.on('data', function(chunk) {
                        body += chunk;
                    });

                    res.on('end', function() {
                        jsonRes = JSON.parse(body);
                        callback.apply(null, [idx, jsonRes.interestScore]);
                    });
                }).on('error', function(e) {
                    console.log("Got error: ", e);
                });
            })(i);
        }

    });
}).on('error', function(e) {
    console.log("Got error: ", e);
});
};
exports.someFunc = someFunc;

When I call the function to retrieve the 5 values I do it like this :

exports.featured = function(req, res){
    getSome.someFunc(function callback(result) {
        var variables = {};
        var variableName = result;
        variables[variableName] = jsonRes.interestScore;
        res.render('featured', { score0: variables[0], score1: variables[1], score2: variables[2], score3: variables[3], score4: variables[4] });
    });
};

Unfortunately 'res.render' is called after the function retrieved only 1 value, so I want to know how to do it proprely, or make a proper callback.

Thanks.

The function you call is async, response end events can be happening anytime. And your code causes res.render to execute 5 times, but you only need it to execute 1 time with 5 values. You should be using a module like async which will help you to fire multiple tasks, and callback when all of them is finished.

Example:

var jsonResult = JSON.parse(body);
var arr = [];
for(var i = 0; i < 5; i++){
   arr.push(jsonResult[0].interestScore);
}
async.map(arr, myAsyncFunction, function(err, results){
   // results[0] => response of first index
   // results[4] => response of last index
});

The first problem which I'm seeing is that you are assigning listener for the end event five times. You should do that only once. You can collect the result five times and after that call the callback. Here is an example which uses request module:

var request = require('request');

var makeRequests = function(callback) {
    var result = [],
        done = 0;
    request('http://www.google.com', function (error, response, body) {
        if (!error && response.statusCode == 200) {
            // read the body here
            var searchFor = [
                'nodejs',       // 1
                'http request', // 2
                'npm',          // 3
                'express',      // 4
                'javascript'    // 5
            ];
            for(var i=0; keyword = searchFor[i]; i++) {
                request('https://www.google.bg/search?q=' + keyword, function (error, response, body) {
                    if (!error && response.statusCode == 200) {
                        result.push(body);
                        ++done;
                        if(done == searchFor.length) {
                            callback(result);
                        }
                    }
                });
            }
        }
    });
}

makeRequests(function(result) {
    console.log("result=" + result.length);
})

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