2016-04-01 14 views
0

Wie soll ich meine rekursive Schleife schreiben, um Versprechungen in Reihenfolge korrekt auszuführen? Ich habe es mit Promise.all versucht (Array.map (function() {})); was nicht meinen Bedürfnissen entspricht, da diese Schritte in einer Sequenz ausgeführt werden müssen. Ich habe es mit einem benutzerdefinierten Versprechen versucht, weil ich here gefunden habe, aber es hat auch Probleme.Javascript versprechen Rekursion und Verkettung

Das Versprechen für:

var promiseFor = (function(condition, action, value) { 
    var promise = new Promise(function(resolve, reject) { 
     if(!condition(value)) { 
      return; 
     } 
     return action(value).then(promiseFor.bind(null, condition, action)); 
    }); 
    return promise; 
}); 

Das Problem dabei ist, dass für sie am tiefsten rekursiven Aufruf zu stoppen scheint die Schleife die Ausführung der Rückkehr nicht mehr weiter richtig zu beenden.

Zum Beispiel: in PHP ein Code wie folgt aus:

function loopThrough($source) { 
    foreach($source as $value) { 
     if($value == "single") { 
      //do action 
     } else if($value == "array") { 
      loopThrough($value); 
     } 
    } 
} 

Wenn ich können eine Ordnerstruktur sagen übergeben und „Single“ bedeutet Datei, werden alle Dateien drucken. Aber das Versprechen, das ich benutze, stoppt an der ersten Sackgasse.

EDIT: Hinzugefügt Bluebird um zu sehen, ob es mit etwas helfen konnte, immer noch das Gleiche. Hier ist die Stromschleife Code

var runSequence = (function(sequence, params) { 
    return Promise.each(sequence, function(action) { 
     console.log(action['Rusiavimas'] + ' - ' + action['Veiksmas']); 
     if(params.ButtonIndex && params.ButtonIndex != action['ButtonIndex']) { 
      return Promise.resolve(); 
     } 

     if(action['Veiksmas'].charAt(0) == '@') { 
      var act = action['Veiksmas']; 
      var actName = act.substr(0, act.indexOf(':')).trim(); 
      var actArg = act.substr(act.indexOf(':')+1).trim(); 

      /* This one is the code that figures out what to do and 
       also calls this function to execute a sub-sequence. */ 
      return executeAction(actName, actArg, params); 
     } else { 
      sendRequest('runQuery', action['Veiksmas']); 
     } 
    }); 
}); 

I 3-Sequenzen haben, die jeweils aus 5 Aktionen. Erste und zweite Sequenz hat die nächste Sequenz als dritte Aktion. Hier ist das Ergebnis, das ich bekommen (Zahlen bedeuten die Reihenfolge):

1 - @PirmasVeiksmas 
1 - @AntrasVeiksmas 
1 - @Veiksmas: list_two 
2 - @PirmasVeiksmas 
2 - @AntrasVeiksmas 
2 - @Veiksmas: list_three 
3 - @PirmasVeiksmas 
3 - @AntrasVeiksmas 
3 - @TreciasVeiksmas 
3 - @KetvirtasVeiksmas 
3 - @PenktasVeiksmas 

Wie Sie sehen es die nächste Sequenz eintritt und weiter wie es sollte, aber sobald der dritte abgeschlossen ist, sollte es die zweite Folge und Ende wieder aufnehmen mit dem ersten auf. Aber es stoppt, sobald es die erste Sackgasse in der Rekursion erreicht.

EDIT2: Codepen Beispiel dafür, was ich habe jetzt und mit visueller Darstellung von dem, was passiert: Codepen link

ausgegeben werden soll:

fa1 
second 
sa1 
third 
ta1 
ta2 
ta3 
sa3 
fa3 
+0

ist das PHP-Code asynchron? – dandavis

+0

@dandavis nein, es war nur ein Beispiel, ich kann einfach nicht herausfinden, warum die Kette der Versprechen aufhört, wenn sie die erste Sackgasse erreicht und einen Schritt (Rekursion) zurückgehen muss, um die vorherige für fortzusetzen. – IntoDEV

+0

Bitte zitieren Sie immer wo Sie Code gefunden haben - schreiben Sie dem Autor einen Link zu! BTW, [hier ist das Original] (http://Stackoverflow.com/a/24660323/1048572) (die auch nicht den Fehler hat) – Bergi

Antwort

0

Also das die Probleme mit Ihrem codepen Code fixiert, so dass es das gibt gewünschte Ausgabe.

var sequences = { 
    first: ['fa1', 'second', 'fa3'], 
    second: ['sa1', 'third', 'sa3'], 
    third: ['ta1', 'ta2', 'ta3'] 
}; 

var loopThrough = (function(sequence) { 
    return sequence.forEach(function(action) { 
    return doAction(action); 
    }); 
}); 

var doAction = (function(action) { 
    var promise = new Promise(function(resolve, reject) { 
    console.log(action); 
    if(action == 'second' || action == 'third') { 
     //recurse into sub-sequence 
     return loopThrough(sequences[action]); 
    } else { 
     //do something here 
    } 
    resolve(); 
    }); 
    return promise; 
}); 

loopThrough(sequences.first); 
1

eine Reihe von Aktionen in einer Sequenz betrieben wird, kann mit .reduce() statt .map() erfolgen.

Hier ein Beispiel:

// Helper function that creates a Promise that resolves after a second 
 
const delay = (value) => new Promise(resolve => setTimeout(() => resolve(value), 1000)); 
 

 
const arr = [1, 2, 3, 4, 5]; 
 

 
// concurrent resolution with `.map()` and `Promise.all()` 
 
Promise.all(arr.map(delay)) 
 
    .then(console.log.bind(console)); // [1, 2, 3, 4, 5] after a second. 
 

 
// sequential resolution with `.reduce()` 
 

 
arr.reduce((promise, current) => 
 
      promise 
 
       .then(() => delay(current)) 
 
       .then(console.log.bind(console)), 
 
      Promise.resolve()); 
 
// second wait, 1, second wait, 2...

Wenn ich richtig Ihre Anforderungen verstanden, Sie müssen nicht genau Rekursion Versprechen, es ist nur so, wie Sie Promises gefunden nacheinander auszuführen. .reduce() kann Ihnen damit einfacher helfen.

Der Reduktionsprozess dreht [1,2,3,4,5] in:

Promise.resolve() 
    .then(() => delay(1)) 
    .then(console.log.bind(console)) 
    .then(() => delay(2)) 
    .then(console.log.bind(console)) 
    .then(() => delay(3)) 
    .then(console.log.bind(console)) 
    .then(() => delay(4)) 
    .then(console.log.bind(console)) 
    .then(() => delay(5)) 
    .then(console.log.bind(console)) 

Beachten Sie, dass, wenn Sie möchten, dass alle die Ergebnisse zugreifen zu können, müssen Sie ein bisschen mehr Arbeit zu tun.Aber ich lasse das als Übung für den Leser :)

+0

Danke, aber ich habe dieses Problem bereits mit einer anderen Stackoverflow-Frage gelöst, stellt sich heraus, dass ich Probleme mit jQuery 2.x hatte, da ich nach 3.x das Problem selbst gelöst habe. Ich habe jQuery nicht in den Versprechungen selbst verwendet, um sie unabhängig zu halten, aber nur indem ich jQuery in meinem Code ein paar Dinge vermasselt habe. Edit: Wenn Sie interessiert sind hier ist der Beitrag [Link] (http://stackoverflow.com/questions/36426786/why-does-this-ajax-request-with-promises-break-the-code-as-running -es-ohne-) – IntoDEV