Більш чистою альтернативою запропонованому @Ivo буде Черга асинхронних методів , припускаючи, що вам потрібно зробити лише один асинхронний виклик для колекції.
(Дивіться цю публікацію Дастіна Діаза для більш детального пояснення)
function Queue() {
this._methods = [];
this._response = null;
this._flushed = false;
}
(function(Q){
Q.add = function (fn) {
if (this._flushed) fn(this._response);
else this._methods.push(fn);
}
Q.flush = function (response) {
if (this._flushed) return;
this._response = response;
while (this._methods[0]) {
this._methods.shift()(response);
}
this._flushed = true;
}
})(Queue.prototype);
Ви просто створюєте новий екземпляр Queue, додаєте потрібні зворотні виклики, а потім змиваєте чергу з асинхронною відповіддю.
var queue = new Queue();
queue.add(function(results){
for (var result in results) {
}
});
someFunction(param1, param2, function(results) {
queue.flush(results);
}
Додатковою перевагою цього шаблону є те, що ви можете додати до черги кілька функцій, а не лише одну.
Якщо у вас є об'єкт, що містить функції ітератора, ви можете додати підтримку для цієї черги за кулісами та написати код, який виглядає синхронно, але це не так:
MyClass.each(function(result){ ... })
просто напишіть, eachщоб помістити анонімну функцію в чергу, а не виконувати її негайно, а потім очистіть чергу, коли завершиться ваш асинхронний виклик. Це дуже простий і потужний шаблон дизайну.
PS Якщо ви використовуєте jQuery, ви вже маєте у своєму розпорядженні чергу асинхронних методів під назвою jQuery.Deferred .
( /* ... */ )схожа на монстра, і я зараз боюся :(