Bardziej przejrzystą alternatywą dla tego, co zasugerował @Ivo, byłaby kolejka metod asynchronicznych , przy założeniu, że wystarczy wykonać jedno wywołanie asynchroniczne dla kolekcji.
(Zobacz ten post Dustina Diaza, aby uzyskać bardziej szczegółowe wyjaśnienie)
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);
Wystarczy utworzyć nowe wystąpienie programu Queue, dodać potrzebne wywołania zwrotne, a następnie opróżnić kolejkę z odpowiedzią asynchroniczną.
var queue = new Queue();
queue.add(function(results){
for (var result in results) {
}
});
someFunction(param1, param2, function(results) {
queue.flush(results);
}
Dodatkową zaletą tego wzorca jest to, że można dodać wiele funkcji do kolejki zamiast tylko jednej.
Jeśli masz obiekt, który zawiera funkcje iteratora, możesz dodać obsługę tej kolejki za kulisami i napisać kod, który wygląda na synchroniczny, ale taki nie jest:
MyClass.each(function(result){ ... })
po prostu napisz, eachaby umieścić anonimową funkcję w kolejce, zamiast wykonywać ją natychmiast, a następnie opróżnij kolejkę po zakończeniu wywołania asynchronicznego. To bardzo prosty i mocny wzorzec projektowy.
PS Jeśli używasz jQuery, masz już do dyspozycji kolejkę metod asynchronicznych o nazwie jQuery.Deferred .
( /* ... */ )wygląda jak potwór i teraz się boję :(