Ronin
Ronin

Reputation: 7950

asynchronous operations result in insonsistent results

I'm new to nodejs and struggling with its asynchronous behaviour. What I want to do is writing an REST API, which will consumes other APIs and is dependent on these results. What I tried to do is capsuling the calls into functions [1] and collect the data and do something with it [2] before I send it to the caller of my API. The problem is that at the time I'm collecting [2] the data, the callApiX functions [1] are still running which will end up in undefined values. Also, I need to call some of the functions more than 1 time and compare the values.

[1] Functions to call APIs:

function callApi1() {
    var result =
    {
        "code": "",
        "name": "",
        "lat": 0,
        "lng": 0
    };
    var request = require("request");
    var url = "someurl";
    request({
        url: url,
        json: true
    }, function (error, response, body) {
        if (!error && response.statusCode === 200) {

            // fill result
            result.code = body.code; // etc.

            // the correct result is being displayed
            console.log(result);

            return result;
        }
    })
}

function callApi2() // ...

[2] get Data from functions and add to request

var express    = require('express');
var router = express.Router();

app.route('/api')
.get(function(req, res) {

    // array for results
    var results = [];

    // all this data is going to be undefined, since the callApiX functions [1] are still running
    results += callApi1();
    results += callApi2();
    results += callApi3();

    // do something with the data collected in results before being sent back to the caller of my API

    res.json(results); // output: {undefinedundefinedundefined}

});

How could I possibly solve this?

Upvotes: 0

Views: 65

Answers (1)

Oleksandr T.
Oleksandr T.

Reputation: 77482

There are several ways (nested callbacks, promises ... ) how you can achieve what you want, one of them you can see below

Example how you can solve this problem with use async,

npm install async

JS:

var async = require('async');    

function callApi1 (callback) {
    var result =
    {
        "code": "",
        "name": "",
        "lat": 0,
        "lng": 0
    };
    var request = require("request");
    var url     = "someurl";

    request({
        url: url,
        json: true
    }, function (error, response, body) {
        if (!error && response.statusCode === 200) {
            result.code = body.code;
            return callback(null, result)
        } else {
            callback(error);
        }
    })
}

function callApi2() // ...


var express    = require('express');
var router = express.Router();

app.route('/api')
.get(function(req, res) {

    async.parallel([
        function(callback){
            callApi1(callback);
        },
        function(callback) {
            callApi2(callback);
        },
        function(callback){
            callApi3(callback);
        }
    ], function (err, results) {
        res.json(results);
    });

});

What function parallel do, from doc

Run the tasks array of functions in parallel, without waiting until the previous function has completed. If any of the functions pass an error to its callback, the main callback is immediately called with the value of the error. Once the tasks have completed, the results are passed to the final callback as an array.

Upvotes: 1

Related Questions