How to await and return the result of a http.reque

2019-02-13 02:15发布

问题:

Assume there is a function doRequest(options), which is supposed to perform an HTTP request and uses http.request() for that.

If doRequest() is called in a loop, I want that the next request is made after the previous finished (serial execution, one after another). In order to not mess with callbacks and Promises, I want to use the async/await pattern (transpiled with Babel.js to run with Node 6+).

However, it is unclear to me, how to wait for the response object for further processing and how to return it as result of doRequest():

var doRequest = async function (options) {

    var req = await http.request(options);

    // do we need "await" here somehow?
    req.on('response', res => {
        console.log('response received');
        return res.statusCode;
    });
    req.end(); // make the request, returns just a boolean

    // return some result here?!
};

If I run my current code using mocha using various options for the HTTP requests, all of the requests are made simultaneously it seems. They all fail, probably because doRequest() does not actually return anything:

describe('Requests', function() {
    var t = [ /* request options */ ];
    t.forEach(function(options) {
        it('should return 200: ' + options.path, () => {
            chai.assert.equal(doRequest(options), 200);
        });
    });
});

回答1:

async/await work with promises. They will only work if the async function your are awaiting returns a Promise.

To solve your problem, you can either use a library like request-promise or return a promise from your doRequest function.

Here is a solution using the latter.

function doRequest(options) {
  return new Promise ((resolve, reject) => {
    let req = http.request(options);

    req.on('response', res => {
      resolve(res);
    });

    req.on('error', err => {
      reject(err);
    });
  }); 
}

describe('Requests', function() {
  var t = [ /* request options */ ];
  t.forEach(function(options) {
    it('should return 200: ' + options.path, async function () {
      try {
        let res = await doRequest(options);
        chai.assert.equal(res.statusCode, 200);
      } catch (err) {
        console.log('some error occurred...');
      }
    });
  });
});


回答2:

you should be able to just pass done to your it function. then, after an async req is done, you would add line done() after your asserts. If there is an error, you would pass it to the done function like done(myError)

https://mochajs.org/#asynchronous-code for more info