Более чистой альтернативой тому, что предложил @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 .
( /* ... */ )похоже на монстра, и теперь мне страшно :(