2014-05-09 3 views
7

Ich schreibe einen Angular.js-Dienst, um einige JSON Feeds zu ziehen. Anfänglich weiß der Dienst nicht, welche/wie viele Ressourcen anzufordern sind; Sie sind abhängig von IDs, die von einer anderen Anfrage zurückgegeben werden.Javascript Angular: wie unbekannte Anzahl von Versprechen zu verketten

Ich habe Kopfschmerzen die $http Service-Anfragen zusammen verketten. Gibt es ein allgemein verwendetes Muster, um dies zu tun?

Ich habe versucht, die Array.reduce Technik in einem anderen Thread vorgeschlagen, hatte aber Probleme beim Synchronisieren der IDs und der angeforderten Daten.

Das ist was ich bisher habe. Hat jemand irgendwelche Vorschläge?

aService.factory('dummy', function($http){ 
    // Dummy resources. 
    var resources = [ 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js', 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js', 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js' 
    ]; 
    return { 
     data: function(callback){ 

      var jquerySources = [] 

      var promiseChain = $http({method: 'GET', url: resources[0]}); 
      var l = resources.length 
      for (var i = 1; i < l; i++){ 
       promiseChain.then(function(data){ 

        jquerySources.push({ 
         url: resources[i], 
         source: data 
        }); 

        promise_chain = $http({method: 'GET', url: resources[i]}); 
        if (i === l){ 
         return callback(jquerySources); 
        } 
       }); 
      } 
     } 
    } 
}); 

Thankyou.

+0

Haben Sie tatsächlich benötigen, um jede Ressource wiederum zu laden? Wenn nicht, können Sie nicht einfach mehrere Anfragen auslösen und dann warten, bis alle Versprechen gelöst sind? – codemonkey

+0

Benötigen Sie sie sequentiell auszuführen oder können sie parallel laufen? –

Antwort

6

Wenn Sie Anforderungen nacheinander tun müssten, würden Sie ein Versprechen erstellen, das Sie als Kopf Ihrer Kette verwenden könnten. Dann könnten Sie Kette $ http Anrufe an diesem Kopf nach oben und lösen den Kopf Versprechen:

aService.factory('seq', function($http, $q){ 
    // Dummy resources. 
    var resources = [ 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js', 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js', 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js' 
    ]; 
    var deferred = $q.defer(); 
    var resourcePromise = deferred.promise; 
    var res = []; 
    angular.forEach(resources, function(resource){ 
     return resourcePromise.then(function(){ 
     return $http({ method: 'GET', url: resource }); 
     }).then(function(data){ 
     res.push({res: resource, data : data}); 
     }); 
    }); 

    deferred.resolve(); 

    return { 
     getResource: resourcePromise.then(function(){ 
      return res; 
     }) 
    }; 
}); 

aber wenn Anfragen parallel wäre - dann wäre es simplier Lösung sein. Nur eine Reihe von Versprechen und rufen Sie einfach $ q.all-Funktion für das Warten auf alle Versprechen zu lösen.

aService.factory('par', function($http, $q){ 
    // Dummy resources. 
    var resources = [ 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js', 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js', 
     'http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js' 
    ]; 
    var promises = []; 
    var res = []; 
    angular.forEach(resources, function(resource){ 
     promises.push(
     $http({ method: 'GET', url: resource }).then(
      function(data){ 
      res.push({res: resource, data : data}); 
      }) 
     ); 
    }); 

    return { 
     getResource: $q.all(promises).then(function(){ 
      return res; 
     }) 
    }; 
}); 

Beachten Sie auch, dass wir in beiden Fällen res-Array zum Sammeln von Ergebnissen von Anfragen haben.

EDIT: Plunker with example

+0

Ich war nur auf der Suche nach etwas Ähnlichem, und das ist super Oleksii. Ein bisschen eine Bauernfrage, aber ich versuchte dann, diese Daten in einen Controller zu bekommen und Probleme zu haben. Ich kann console.log die Daten in der Funktion $ http in der Fabrik, aber nicht in der Lage, die Ausgabe in Json in einen Bereich var in einem Controller zu bekommen. Hast du Vorschläge, wie du das am besten machst? –

+0

Ja, bassisch müssen Sie die Funktion .then() nach dem Aufruf eines Dienstes verwenden. Ich habe gerade meine Antwort mit einem Beispiel ergänzt, werfen Sie einen Blick darauf. –

+0

brilliant, vielen Dank Oleksii, ich schätze es wirklich. Ich habe gerade deine Antwort erneuert. Danke für die Hilfe. –

2

können Sie in der Tat dies tun, reduzieren mit:

var chain = resources.reduce(function (sourcesPromise, url) { 
    return sourcesPromise.then(function (sources) { 
     return $http({method: 'GET', url: url}) 
     .then(function (data) { 
      sources.push({url: url, source: data}); 

      return sources; 
     }); 
    }); 
}, $q.when([])); 

chain.then(function (sources) { 
    // [{url, source}, ...] 
}); 

basierend auf basierend auf How to chain a variable number of promises in Q, in order?