javascript - Hur gör man en ren asynkron loop?
Följande typiska REST-standarder delade jag upp mina resurser i separata endpoints och anrop. De två huvudobjekten som är aktuella här är List och Item (och förstås har en lista en lista med objekt, samt en del annan data kopplad till den).
Så om en användare vill hämta sina listor kan han göra en Get-förfrågan till api/Lists
Då kanske användaren vill hämta objekten i en av dessa listor och göra en Get till api/ListItems/4 där 4 hittades från List.listId som hämtades i det föregående anropet.
Detta är allt bra och väl: options.complete-attributet av $.ajax låter mig peka på en callback-metod, så att jag kan effektivisera dessa två händelser.
Men det blir väldigt rörigt om jag vill hämta elementen för alla listorna i fråga. Till exempel, låt oss anta att jag har en biblioteksfunktion som heter makeGetRequest som tar slutpunkten och callback-funktionen, för att göra denna kod renare. Att helt enkelt hämta 3 element på det naiva sättet resulterar i detta:
var success1 = function(elements){
var success2 = function(elements){
makeGetRequest("api/ListItems/3", finalSuccess);
}
makeGetRequest("api/ListItems/2", success2);
}
makeGetRequest("api/ListItems/1", success1);
Äckligt! Detta är typen av saker i programmering 101 där man får smäll på händerna och pekas mot loopar. Men hur kan man göra detta med en loop, utan att behöva förlita sig på extern lagring?
for(var i : values){
makeGetRequest("api/ListItems/" + i, successFunction);
}
function successFunction(items){
//I am called i-many times, each time only having ONE list's worth of items!
}
Och även med lagring skulle jag behöva veta när alla har avslutat och hämtat sina data, och kalla på någon huvudfunktion som hämtar all insamlad data och gör något med den.
Finns det en praxis för att hantera detta? Detta måste ha lösts många gånger tidigare...
Svar #1
Försök att använda en lista med slutpunktparametrar:
var params = [];
var results [];
params.push({endpoint: "api/ListItems/1"});
params.push({endpoint: "api/ListItems/2"});
params.push({endpoint: "api/ListItems/3"});
params.push({endpoint: "api/ListItems/4"});
Då kan du göra det rekursivt i din framgångshanterare:
function getResources(endPoint) {
var options = {} // Ajax Options
options.success = function (data) {
if (params.length > 0) {
results.push({endpoint: endpoint, data: data});
getResources(params.shift().endpoint);
}
else {
theMasterFunction(results)
}
}
$.get(endPoint, options)
}
Och du kan starta det med ett enda samtal som detta:
getResources(params.shift().endpoint);
Redigera:
För att hålla allt självcontainat och utanför global scope kan du använda en funktion och tillhandahålla en callback:
function downloadResources(callback) {
var endpoints = [];
var results [];
endpoints.push({endpoint: "api/ListItems/1"});
endpoints.push({endpoint: "api/ListItems/2"});
endpoints.push({endpoint: "api/ListItems/3"});
endpoints.push({endpoint: "api/ListItems/4"});
function getResources(endPoint) {
var options = {} // Ajax Options
options.success = function (data) {
if (endpoints.length > 0) {
results.push({endpoint: endpoint, data: data});
getResources(endpoints.shift().endpoint);
}
else {
callback(results)
}
}
$.get(endPoint, options)
}
getResources(endpoints.shift().endpoint);
}
I användning:
downloadResources(function(data) {
// Do stuff with your data set
});
Svar #2
dmcks svar är förmodligen ditt bästa alternativ. Ett annat alternativ är dock att göra ett alternativ med bulklista, så att ditt API stöder förfrågningar som api/ListItems/?id=1&id=2&id=3.
Du skulle också kunna göra en API-sökningsendpoint, om det passar din personliga estetik bättre.
