2015-03-31 17 views
15

Ich versuche, eine while-Schleife mit Versprechen zu implementieren.While-Schleife mit Bluebird verspricht

Die hier beschriebene Methode scheint zu funktionieren. http://blog.victorquinn.com/javascript-promise-while-loop verwendet es eine Funktion wie diese

var Promise = require('bluebird'); 

var promiseWhile = function(condition, action) { 
    var resolver = Promise.defer(); 

    var loop = function() { 
     if (!condition()) return resolver.resolve(); 
     return Promise.cast(action()) 
      .then(loop) 
      .catch(resolver.reject); 
    }; 

    process.nextTick(loop); 

    return resolver.promise; 
}; 

Dies scheint anti-Muster zu verwenden und veraltete Methoden wie Guss- und verschieben.

Kennt jemand einen besseren oder moderneren Weg, dies zu erreichen?

Dank

+0

Können Sie in Worten zu erklären, was Sie wirklich zu tun versuchen? Denken Sie daran, dass eine "busy-wait" -Schleife in JavaScript eine schreckliche Sache ist. Es ist viel sinnvoller, eine Art Event-Handler zu verwenden, anstatt wiederholt etwas in einer engen Schleife aufzurufen. Und was macht 'action()'? Vielleicht ein Beispiel zeigen, wie Sie das benutzen würden? – jfriend00

Antwort

19

cast kann resolve übersetzt werden. defer sollte indeed not be used.

Sie würden Ihre Schleife nur durch Verkettung und Verschachtelung von then Invokationen auf eine ursprüngliche Promise.resolve(undefined) erstellen.

function promiseWhile(predicate, action, value) { 
    return Promise.resolve(value).then(predicate).then(function(condition) { 
     if (condition) 
      return promiseWhile(predicate, action, action()); 
    }); 
} 

Hier sind sowohl predicate und action kann Versprechungen zurück. Für ähnliche Implementierungen auch einen Blick auf Correct way to write loops for promise. Näher an Ihrer ursprünglichen Funktion

function promiseWhile(predicate, action) { 
    function loop() { 
     if (!predicate()) return; 
     return Promise.resolve(action()).then(loop); 
    } 
    return Promise.resolve().then(loop); 
} 
+0

Sie können die 'loop' -Funktion ändern, um einen Wert zu akzeptieren und dann auflösen, wenn das Prädikat false ist, nur um den letzten von der' action' Funktion zurückgegebenen Wert zu erhalten. – Sami

+0

@Sami: Ja, [die Antwort in der verknüpften Frage] (http://stackoverflow.com/a/24660323/1048572) macht das zum Beispiel. Jedoch wollte ich diese Antwort nahe bei der OP-Funktion halten, die immer zu 'undefiniert' führt. – Bergi

+0

Kannst du ein Beispiel deines 'promiseWhile' in Aktion zeigen? Ziemlich verwirrt hier über wie man es tatsächlich benutzt. –

3

ich diese Implementierung lieber als wäre einfacher haben Pause zu simulieren und damit weiter:

var Continue = {}; // empty object serves as unique value 
var again = _ => Continue; 

var repeat = fn => Promise.try(fn, again) 
    .then(val => val === Continue && repeat(fn) || val); 

Beispiel 1: stoppt, wenn entweder die Quelle oder das Ziel einen Fehler anzeigen

repeat(again => 
    source.read() 
    .then(data => destination.write(data)) 
    .then(again) 

Beispiel 2: Nach dem Zufall stoppen, wenn die Münzflip 90% Wahrscheinlichkeit Ergebnisse entsprechen wit h a 0

var blah = repeat(again => 
    Promise.delay(1000) 
    .then(_ => console.log("Hello")) 
    .then(_ => flipCoin(0.9) && again() || "blah")); 

Beispiel 3: Schleife mit Bedingung, dass die Summe zurück:

repeat(again => { 
    if (sum < 100) 
    return fetchValue() 
     .then(val => sum += val) 
     .then(again)); 
    else return sum; 
}) 
+1

Ich würde wahrscheinlich ein 'Symbol' für einen einzigartigen Wert verwenden, sieht aber ansonsten gut aus :) –

+0

gott thinking benji –