如何运行多个异步函数然后执行回调

时间:2015-09-28 17:14:20

标签: javascript node.js api

在我的NodeJS代码中,我需要进行2或3次API调用,每次调用都会返回一些数据。完成所有API调用后,我想将所有数据收集到一个JSON对象中以发送到前端。

我知道如何使用API​​回调执行此操作(下一次调用将在之前的调用回调中发生),但这会很慢:

//1st request
request('http://www.example.com', function (err1, res1, body) {

  //2nd request
  request('http://www.example2.com', function (err2, res2, body2) {

    //combine data and do something with it

  });

});

我知道你也可以做一些与承诺相似的事情,但是我认为同样的概念适用于下一次调用在当前调用完成之前执行的情况。

有没有办法同时调用所有函数,但我的最后一段代码是等待所有API调用完成并在执行之前提供数据?

4 个答案:

答案 0 :(得分:47)

Promises为您提供Promise.all()(对于原生承诺以及像bluebird这样的图书馆承诺)。

更新:从节点8开始,您可以像使用Bluebird的util.promisify()

一样使用.promisify()
var requestAsync = util.promisify(request); // const util = require('util')
var urls = ['url1', 'url2'];
Promise.all(urls.map(requestAsync)).then(allData => {
    // All data available here in the order of the elements in the array
});

那么你可以做什么(本机):

function requestAsync(url) {
    return new Promise(function(resolve, reject) {
        request(url, function(err, res, body) {
            if (err) { return reject(err); }
            return resolve([res, body]);
        });
    });
}
Promise.all([requestAsync('url1'), requestAsync('url2')])
    .then(function(allData) {
        // All data available here in the order it was called.
    });

如果你有蓝鸟,这甚至更简单:

var requestAsync = Promise.promisify(request);
var urls = ['url1', 'url2'];
Promise.all(urls.map(requestAsync)).then(allData => {
    // All data available here in the order of the elements in the array
});

答案 1 :(得分:12)

如果你想使用异步,听起来像async.parallel()也可以完成这项工作:

var async = require('async');

async.parallel({
    one: function(parallelCb) {
        request('http://www.example1.com', function (err, res, body) {
            parallelCb(null, {err: err, res: res, body: body});
        });
    },
    two: function(parallelCb) {
        request('http://www.example2.com', function (err, res, body) {
            parallelCb(null, {err: err, res: res, body: body});
        });
    },
    three: function(parallelCb) {
        request('http://www.example3.com', function (err, res, body) {
            parallelCb(null, {err: err, res: res, body: body});
        });
    }
}, function(err, results) {
    // results will have the results of all 3
    console.log(results.one);
    console.log(results.two);
    console.log(results.three);
});

答案 2 :(得分:1)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Promise.all现已包含在ES6中,因此您根本不需要任何第三方库。

" Promise.all等待所有履行(或第一次拒绝)"

我已经设置了一个要点,以演示Promise.all()并在以下位置重构itterations:https://gist.github.com/rainabba/21bf3b741c6f9857d741b69ba8ad78b1

我正在使用IIFE(立即涉及函数表达式)。如果您不熟悉,虽然要点显示了如何使用IIFE,但您希望成为下面的示例。 https://en.wikipedia.org/wiki/Immediately-invoked_function_expression

TL; DR

( function( promises ){
    return new Promise( ( resolve, reject ) => {
        Promise.all( promises )
            .then( values => {
                console.log("resolved all promises")
                console.dir( values );
                resolve( values.reduce( (sum,value) => { return sum+value }) ); //Use Array.prototype.reduce() to sum the values in the array
            })
            .catch( err => {
                console.dir( err );
                throw err;
            });

    });
})([ 
    new Promise( ( resolve, reject ) => {
        console.log("resolving 1");
        resolve( 1 );
    }),
    new Promise( ( resolve, reject ) => {
        console.log("resolving 2");
        resolve( 2 );
    })
 ]).then( sum => { console.dir( { sum: sum } ) } )

答案 3 :(得分:1)

我有一个类似的用例,我必须同时进行 10 个调用。我是通过 async/awaitPromise.all 的组合做到的。

async function getData() {
  try {
    let result = null
    const ids = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]

    let promises = ids.map(async (id) => {
        return fetch(
          `https://jsonplaceholder.typicode.com/todos/${id}`
        ).then((data) => data.json());
      });
    
    result = await Promise.all(promises)
    return result
  } catch(err) {
    console.log("error: ", err)
  }
}

getData().then(data => console.log(data))

相关问题