2012-04-24 5 views
14

Каков наилучший способ/библиотека для обработки нескольких асинхронных обратных вызовов? Прямо сейчас, у меня есть что-то вроде этого:Javascript - ожидаете возвращения асинхронных обратных вызовов?

_.each(stuff, function(thing){ 
    async(thing, callback); 
}); 

Мне нужно выполнить некоторый код после обратного вызова был обстрелян для каждого элемента в stuff.

Какой самый чистый способ сделать это? Я открыт для использования библиотек.

+0

возможно дубликат [Ожидание на несколько асинхронных вызовов, прежде чем продолжать] (http://stackoverflow.com/questions/2768293/waiting-on-multiple-asynchronous-calls-to-complete-before-continuing) – RMalke

ответ

12

Существует большая библиотека под названием Async.js, которая помогает решить такие проблемы, как это, с помощью многих async & помощников по управлению потоком. Он предоставляет несколько функций forEach, которые могут помочь вам выполнить обратные вызовы для каждого элемента в массиве/объекте.

Отъезд: https://github.com/caolan/async#forEach

// will print 1,2,3,4,5,6,7,all done 

var arr = [1,2,3,4,5,6,7]; 

function doSomething(item, done) { 
    setTimeout(function() { 
    console.log(item); 
    done(); // call this when you're done with whatever you're doing 
    }, 50); 
} 

async.forEach(arr, doSomething, function(err) { 
    console.log("all done"); 
}); 
+0

Это хорошо, и если это может справиться с цепью для меня, я могу сделать этот переключатель позже. Делает ли это что-то более разумное, чем просто использовать счетчик, например _.after? –

+0

Замечательно, что вы можете сделать 'async.forEachSerial', если хотите, чтобы они запускались один за другим. Это дает вам гибкость.Для простого случая использования, да, счетный счет отлично работает и встроен в подчеркивание. Сделай это! –

+0

Я получил необходимость использовать «серию» совсем немного, и переход на асинхронную очистку вещей * совсем немного. Я также уверен, что я обнаружил проблему обратного вызова в процессе. –

0

Имейте счетчик, скажем async_count. Увеличьте его на каждый раз, когда вы начинаете запрос (внутри цикла), и его обратный вызов уменьшает его на единицу и проверяет, достиг ли нуль, если это так, все обратные вызовы вернулись.

РЕДАКТИРОВАТЬ: Хотя, если бы я был тем, кто писал это, я бы привязал запросы, а не запускал их параллельно - другими словами, у меня очередь запросов и проверка обратного вызова очереди для следующего запроса делать.

28

Поскольку вы уже используете подчеркивания вы можете посмотреть на _.after. Он делает именно то, о чем вы просите. Из документов:

после       _.after(count, function)

Создает версию функции, которая будет выполняться только после того, как первый раз Называние счета. Полезно для группировки асинхронных ответов, где вы хотите убедиться, что все асинхронные вызовы закончены, прежде чем продолжить.

+1

Это отлично работает. –

2

Я рекомендую https://github.com/caolan/async для этого. Вы можете использовать async.parallel для этого.

function stuffDoer(thing) { 
    return function (callback) { 
     //Do stuff here with thing 
     callback(null, thing); 
    } 
} 

var work = _.map(stuff, stuffDoer) 
async.parallel(work, function (error, results) { 
    //error will be defined if anything passed an error to the callback 
    //results will be an unordered array of whatever return value if any 
    //the worker functions passed to the callback 
} 
+0

Почему бы не 'async.forEach'? –

+0

Я думаю, что в этом случае async.forEach и async.parallel в основном идентичны. Документы on forEach даже говорят, что «он выполняет их параллельно». Однако «параллельное» имя делает это яснее. –

+0

Хм, да, кажется, для этого более подходящим в этом случае, поскольку он будет обрабатывать закрытие для вас, и вы можете просто дать ему регулярную функцию и список данных. –

1

async.parallel()/async.series должны соответствовать вашим требованиям. Вы можете предоставить окончательный обратный вызов, который будет выполнен, когда все вызовы REST будут успешными.

async.parallel([ 
    function(){ ... }, 
    function(){ ... } 
], callback); 
async.series([ 
    function(){ ... }, 
    function(){ ... } 
], callback); 
Смежные вопросы