Vyhledávání na webu

javascript - Jak udělat čistou asynchronní smyčku?


Podle typických standardů REST jsem rozdělil své zdroje do samostatných koncových bodů a volání. Hlavními dvěma objekty, o které zde jde, jsou List a Item (a samozřejmě, seznam má seznam položek, stejně jako některá další data s ním spojená).

Takže pokud chce uživatel získat své seznamy, může provést GET požadavek na api/Lists

Pak by uživatel mohl chtít získat položky v jednom z těchto seznamů a provést GET na api/ListItems/4, kde 4 bylo nalezeno z List.listId získaného v předchozím volání.

To je všechno v pořádku: atribut options.complete $.ajax mi umožňuje odkazovat na zpětnou volací metodu, takže mohu zjednodušit tyto dvě události.

Ale věci se velmi zkomplikuju, pokud chci získat prvky pro všechny seznamy, o kterých je řeč. Například předpokládejme, že mám knihovní funkci nazvanou makeGetRequest, která přijímá koncový bod a zpětnou volací funkci, aby byl tento kód čistší. Pouhé získání 3 prvků na naivní způsob vede k tomuto:

var success1 = function(elements){
    var success2 = function(elements){
       makeGetRequest("api/ListItems/3", finalSuccess);
    }
    makeGetRequest("api/ListItems/2", success2);
}
makeGetRequest("api/ListItems/1", success1);

Odporné! To je ten druh věci, za který nás na programování 101 napomínají a ukazují na smyčky. Ale jak to můžete udělat pomocí smyčky, aniž byste museli spoléhat na externí úložiště?

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!
}

A dokonce i s ukládáním bych musel vědět, kdy všichni dokončili a získali svá data, a zavolat nějakou hlavní funkci, která získá všechna shromážděná data a něco s nimi udělá.

Existuje nějaká praxe pro řešení tohoto? To už muselo být mnohokrát vyřešeno...

Odpověď č. 1

Zkuste použít zásobník parametrů koncového bodu:

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"});

Pak to můžete udělat rekurzivně ve svém handleru úspěchu:

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)
}

A můžete ho spustit jediným voláním takto:

getResources(params.shift().endpoint);

Upravit:

Aby vše zůstalo samostatné a mimo globální oblast, můžete použít funkci a poskytnout zpětné volání:

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);

}

V použití:

downloadResources(function(data) {
   // Do stuff with your data set
});

Odpověď č. 2

Odpověď dmck je pravděpodobně vaše nejlepší volba. Další možností je však použít možnost hromadného seznamu, aby vaše API podporovalo požadavky jako api/ListItems/?id=1&id=2&id=3.

Také byste mohl udělat API vyhledávací endpoint, pokud to více odpovídá vašemu osobnímu vkusu.