Express | Making multiple http requests asynchrono

2020-07-28 08:30发布

问题:

I am currently building a small node application that makes a few api calls and renders a webpage with charts on it. I'm using express and jade as the render engine.

The problem is that I'm quite new to javascript and I don't know how to scheme out my http requests so I can pass an object of variables I got from the api (http get) when there is more than one request. I don't know how to map it out to make a single object and send it to the jade rendering engine.

Here is what I have so far :

app.get('/test', function(req, res) {
    apiRequestGoesHere(name, function(error, profile) {
        //Get some data here
    });
    anotherApiRequest(tvshow, function(error, list) {
        //Get some data here
    });
    res.render('test', data);
});

As it is right now, the page renders and the requests are not done yet, and if I place res.render inside one of the request, I can't access the other's data.

So what I want is a way to set it up so I can have multiple api calls, then make an object out of some elements of what is returned to me from the rest api and send it to Jade so I can use the data on the page.

回答1:

You probably want to use async to help with this. async.parallel is a good choice for something simple like this:

app.get('/test', function(req, res) {
    async.parallel([
    function(next) {
        apiRequestGoesHere(name, function(error, profile) {
            //Get some data here
            next(null, firstData);
        });
    },
    function(next) {
        anotherApiRequest(tvshow, function(error, list) {
            //Get some data here
            next(null, secondData);
        });
    }], function(err, results) {
        // results is [firstData, secondData]
        res.render('test', ...);
    });
});

The first argument to those functions next should be an error if relevant (I put null) - as soon as one is called with an error, the final function will be called with that same error and the rest of the callbacks will be ignored.



回答2:

You can async parallel.

async.parallel([
    function(callback){
        // Make http requests
        // Invoke callback(err, result) after http request success or failure
    },
    function(callback){
        // Make http requests
        // Invoke callback(err, result) after http request success or failure
    }
],
// optional callback
function(err, results){
    // the results array will be array of result from the callback
});


回答3:

The reason your page renders is the callbacks haven't "called back" yet. To do what you want, you would need to do something like:

app.get('/test', function(req, res) {
    apiRequestGoesHere(name, function(error, profile) {
        //Get some data here
        anotherApiRequest(tvshow, function(error, list) {
            //Get some data here
            res.render('test', data);
        });
    });
});

This strategy leads to what is known as "pyramid code" because your nested callback functions end up deeper and deeper.

I would also recommend the step library by Tim Caswell. It would make your code look something like:

var step = require('step');

app.get('/test', function(req, res) {
    step(
        function () {
            apiRequestGoesHere(name, this)
        },
        function (error, profile) {
            if error throw error;
            anotherApiRequest(tvshow, this)
        },
        function done(error, list) {
            if error throw error;
            res.render('test', list)
        }
    )
});

You could also use the group method to make the calls in parallel and still maintain the sequence of your callbacks.

Gl, Aaron