假设我有四个不同的异步操作需要运行,它们都可以独立运行。但是剩下的一个函数需要使用那些异步调用收集的所有数据,因此只有在所有这些数据完成后才能完成。
一种简单的方法是让异步调用一个接一个地相互调用,然后最终调用final函数,如下所示:
myObj.async1(function () {
myObj.async2(function () {
myObj.async3(function () {
myObj.async4(function () {
...
finalFunction();
但这是一种糟糕的方法,因为节点是围绕异步功能构建的。相反,让我们说我们想做:
myObj.async1(async1Callback);
myObj.async2(async2Callback);
myObj.async3(async3Callback);
myObj.async4(async4Callback);
if( //Some logic here to determine when all four functions have completed
finalFunction();
确定逻辑的最佳方法是什么?我考虑让每个函数设置一个布尔变量来指示它是否已经完成,然后让一个基于时间的发射器不断检查是否所有四个变量都设置为true然后调用finalFunction,如果它们是,但是这可能会变得混乱所有这些变数都存在。
有关最佳方法是什么的任何想法?
答案 0 :(得分:4)
我会使用async
库,例如
async.parallel([
myObj.async1,
myObj.async2,
myObj.async3,
myObj.async4
], function(err) {
if (err) throw err;
// Run final function now that all prerequisites are finished
finalFunction();
});
这假定每个myObj.async*
function
都将回调function
作为唯一参数,而回调的第一个参数是err
参数。有关详细信息,请参阅docs for async#parallel()
。
答案 1 :(得分:2)
正如@jabclab推荐的那样,请看一下async,因为它为您管理了大部分复杂性。但是,如果你想自己做这样的事情,可以选择几种方式。
从看起来像的myObj开始:
var myObj = {
async1: function async1(cb) { setTimeout(function() {
console.log('async1');
cb(null, {name: 'async1'});
}, 1000)},
async2: function async2(cb) { setTimeout(function() {
console.log('async2');
cb(null, {name: 'async2'});
}, 500)},
async3: function async3(cb) { setTimeout(function() {
console.log('async3');
cb(null, {name: 'async3'});
}, 1001)},
async4: function async4(cb) { setTimeout(function() {
console.log('async4');
cb(null, {name: 'async4'});
}, 200)}
}
此版本已硬编码,可在结果完成时调用四个特定函数和回调。结果以完成后排序的数组传回。每个结果对象都包含函数的名称以及任何错误或成功结果。
function doFourSpecificThings(callback) {
var results = [];
var storeResults = function(fnName, err, resp) {
results.push( { fnName: fnName, err: err, resp: resp } );
if(results.length === 4 && callback) {
callback(results);
}
}
// Bind the callback to myObj and pass the name of the called function
// as the first argument
myObj.async1(storeResults.bind(myObj, 'async1'));
myObj.async2(storeResults.bind(myObj, 'async2'));
myObj.async3(storeResults.bind(myObj, 'async3'));
myObj.async4(storeResults.bind(myObj, 'async4'));
}
doFourSpecificThings(function(results) {
console.log(results);
});
输出:
async4
async2
async1
async3
Results:
[ { fnName: 'async4', err: null, resp: { name: 'async4' } },
{ fnName: 'async2', err: null, resp: { name: 'async2' } },
{ fnName: 'async1', err: null, resp: { name: 'async1' } },
{ fnName: 'async3', err: null, resp: { name: 'async3' } } ]
这个版本更灵活一些。任务作为数组传入,结果以相同的顺序存储在结果数组中:
function doABunchOfStuff(tasks, callback) {
var results = [];
var expected = tasks.length;
var storeResults = function(idx, err, resp) {
results[idx] = { err: err, resp: resp };
--expected;
if((expected === 0) && callback) {
callback(results);
}
}
// Using bind here to pass the current index to the storeResults()
// callback as the first parameter
for(var i = 0; i < tasks.length; ++i) {
tasks[i](storeResults.bind(tasks[i], i));
}
}
doABunchOfStuff([
myObj.async1.bind(myObj),
myObj.async2.bind(myObj),
myObj.async3.bind(myObj),
myObj.async4.bind(myObj)],
function(results) {
console.log('\nResults:');
console.log(results);
});
输出:
async4
async2
async1
async3
Results:
[ { err: null, resp: { name: 'async1' } },
{ err: null, resp: { name: 'async2' } },
{ err: null, resp: { name: 'async3' } },
{ err: null, resp: { name: 'async4' } } ]