2016-05-31 6 views
2

Ich bin zu der Erkenntnis gekommen, dass seit Versprechungen in ECMAScript 6 synchrone Codierung von asynchronen Funktionen ermöglichen, für jedes Versprechen-geladene Stück Code gibt es eine synchrone Folge. Zum Beispiel:Promise-Version einer "While" -Schleife?

var data = processData(JSON.parse(readFile(getFileName()))); 

ist das gleiche wie:

var data = getFileName() 
    .then(readFile) 
    .then(JSON.parse) 
    .then(processData); 

Jetzt für meinen aktuellen Anwendungsfall mag ich Code schreiben, Daten aus einer massiven öffentlichen API zu ziehen. Die API ist paginierte, so in einer rein synchronen Welt, die ich so etwas wie die folgenden schreiben würde:

var data = []; 
var offset = 0; 
var total = 10000; // For example - not actually how this would work 
while(offset < total) { 
    data.concat(getDataFromAPI(offset)); 
    offset = data.length; 
} 

Nun meine Frage ist, wie würde ich dies tun, mit dem Versprechen?

var data = []; 
var offset = 0; 
var total = 10000; 
getDataFromAPI(offset) 
    .then(function(newData){ 
     data.concat(newData); 
     return getDataFromAPI(data.length); 
    }); 

Aber an diesem Punkt bin ich gezwungen, nur die Kette unendlich .then s - es gibt keine Looping Logik: Ich könnte so etwas wie schreiben. Ich habe das Gefühl, dass etwas mit Rekursion möglich sein sollte, aber ich habe keine Ahnung, wie es geht.

Ich verwende BluebirdJS als meine Versprechen Bibliothek, so habe ich Zugriff auf alle ihre Hilfsmethoden.

+0

Was ist mit einer rekursiven selbstaufrufenden anonymen Funktion (eventuell kombiniert mit Promises)? Hier ist nur ein Beispiel: https://jsfiddle.net/f5ud8ytx/. Ersetzen Sie die Zeitüberschreitung durch Ihren eigenen API-Aufruf und verwenden Sie die .then der vom api-Aufruf zurückgegebenen Zusage, um die Funktion erneut aufzurufen, bis das Ende 0 erreicht (current-- wird ausgeführt, bis das Ende höher als 0 ist) – briosheje

+0

Sie können dies problemlos mit 'tun async-each " – r3wt

Antwort

6

Ich mag das Gefühl etwas sollte möglich sein, mit Hilfe von Rekursion

Genau. Sie können den Rückruf benennen, damit Sie ihn erneut referenzieren können. Solange die Bedingung nicht erfüllt ist, geben Sie eine Zusage aus dem Rückruf zurück. Andernfalls geben Sie das Endergebnis zurück:

getDataFromAPI(offset) 
    .then(function next(newData){ 
    data.concat(newData); 
    var newOffset = data.length; 
    return newOffset < total ? getDataFromAPI(newOffset).then(next) : data; 
    }) 
    .then(function(data) { 
    console.log(data); // final result 
    });