Javascript 如何运行多个异步函数然后执行回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32828415/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to run multiple async functions then execute callback
提问by Coop
In my NodeJS code I need to make 2 or 3 API calls, and each will return some data. After all API calls are complete I want to collect all the data into a single JSON object to send to the frontend.
在我的 NodeJS 代码中,我需要进行 2 或 3 个 API 调用,每个调用都会返回一些数据。在所有 API 调用完成后,我想将所有数据收集到一个 JSON 对象中以发送到前端。
I know how to do this using the API callbacks (the next call will happen in the previous call's callback) but this would be slow:
我知道如何使用 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
});
});
I know you could also do something similar and neater with promises, but I think the same concept applies where the next call won't execute until the current one has finished.
我知道你也可以用 Promise 做一些类似和更简洁的事情,但我认为同样的概念适用于下一个调用直到当前调用完成才会执行的情况。
Is there a way to call all functions at the same time, but for my final block of code to wait for all API calls to complete and supply data before executing?
有没有办法同时调用所有函数,但我的最后一段代码在执行之前等待所有 API 调用完成并提供数据?
回答by Madara's Ghost
Promises give you Promise.all()
(this is true for native promises as well as library ones like bluebird's).
Promise 为您提供Promise.all()
(对于原生 Promise 以及像 bluebird 的库中的 Promise 都是如此)。
Update: Since Node 8, you can use util.promisify()
like you would with Bluebird's .promisify()
更新:从 Node 8 开始,您可以util.promisify()
像使用 Bluebird 一样使用.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
});
So what you can do (native):
那么你可以做什么(本地):
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.
});
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.
});
If you have bluebird, this is even simpler:
如果你有蓝鸟,这更简单:
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
});
回答by Ben
Sounds like async.parallel() would also do the job if you'd like to use async:
如果您想使用异步,听起来 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);
});
回答by rainabba
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
Promise.all is now included with ES6 so you don't need any 3rd party libraries at all.
Promise.all 现在包含在 ES6 中,因此您根本不需要任何 3rd 方库。
"Promise.all waits for all fulfillments (or the first rejection)"
“Promise.all 等待所有履行(或第一次拒绝)”
I've setup a gist to demonstrate Promise.all() with refactoring itterations at: https://gist.github.com/rainabba/21bf3b741c6f9857d741b69ba8ad78b1
我已经设置了一个要点来演示 Promise.all() 与重构 itterations:https://gist.github.com/rainabba/21bf3b741c6f9857d741b69ba8ad78b1
I'm using an IIFE (immediately involved function expression). If you're not familiar, you'll want to be for the example below though the gist shows how with using an IIFE. https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
我正在使用 IIFE(立即涉及的函数表达式)。如果你不熟悉,你会想成为下面的例子,尽管要点显示了如何使用 IIFE。https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
TL;DR
TL; 博士
( 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 } ) } )