2015-10-19 4 views
9

Ich schreibe einen Code für Abfragen für eine Ressource alle N ms, die nach M Sekunden Timeout sollte. Ich möchte, dass das Ganze mit Bluebird so viel wie möglich verspricht. Die Lösung, die ich bisher entwickelt habe, verwendet das Intervall des Knotens, die abrechenbaren Bluebird-Versprechungen und die Timeout-Funktion von Bluebird.Was ist ein gutes Muster für "Intervall mit Timeout" mit Promises

Ich frage mich, ob es eine bessere Möglichkeit gibt, Timing-Out-Intervalle mit Bluebird und Versprechungen im Allgemeinen zu tun? Hauptsächlich, indem sichergestellt wird, dass das Intervall an der Stelle aufhört und niemals unendlich weitergeht.

var Promise = require('bluebird'); 

function poll() { 
    var interval; 

    return new Promise(function(resolve, reject) { 
    // This interval never resolves. Actual implementation could resolve. 
    interval = setInterval(function() { 
     console.log('Polling...') 
    }, 1000).unref(); 
    }) 
    .cancellable() 
    .catch(function(e) { 
     console.log('poll error:', e.name); 
     clearInterval(interval); 
     // Bubble up error 
     throw e; 
    }); 
} 

function pollOrTimeout() { 
    return poll() 
    .then(function() { 
     return Promise.resolve('finished'); 
    }) 
    .timeout(5000) 
    .catch(Promise.TimeoutError, function(e) { 
     return Promise.resolve('timed out'); 
    }) 
    .catch(function(e) { 
     console.log('Got some other error'); 
     throw e; 
    }); 
} 

return pollOrTimeout() 
    .then(function(result) { 
    console.log('Result:', result); 
    }); 

Ausgang:

Polling... 
Polling... 
Polling... 
Polling... 
poll error: TimeoutError 
Result: timed out 

Antwort

5

Ich würde das so etwas wie tun -

function poll() { 
    return Promise.resolve().then(function() { 
    console.log('Polling...'); 
    if (conditionA) { 
     return Promise.resolve(); 
    } else if (conditionB) { 
     return Promise.reject("poll error"); 
    } else { 
     return Promise.delay(1000).then(poll); 
    } 
    }) 
    .cancellable() 
} 

auch von Promise constructor anti-pattern bewusst sein

+1

Schön. Wie würdest du das Intervall abschließen? Sieht wie der einzige Ausweg aus, wenn man einen Fehler wirft. Ich weiß, dass der Promise-Konstruktor ein Anti-Pattern ist, aber in diesem Fall schien es zu passen (dasselbe gilt für Events + Promises, aber das ist ein anderes Thema). – Chris911

+0

Ok jetzt verstehe ich deine Frage. Überprüfen Sie meine Bearbeitung. – vinayr

+0

Ja, das funktioniert. Danke und akzeptierte Antwort. – Chris911

1

Rene Wooller einen wirklich guten Punkt macht:

Warnung: leider Rekursion in Javascript, wie dies wird schließlich den Call-Stack sättigt und führt in den Speichern Ausnahmen

Auch wenn es nicht Ausnahme ist dieser Raum verschwendet wird, und das Risiko einer Ausnahme könnte eine überlange Umfragverspätung fördern.

Ich denke, das ist wichtig genug setInterval bevorzugen:

var myPromise = new Promise((resolve, reject) => { 
    var id = window.setInterval(() => { 
     try { 
      if (conditionA) { 
       window.clearInterval(id); 
       resolve("conditionA"); 
      } else if (conditionB) { 
       throw new Error("conditionB!"); 
      } 
     } catch(e) { 
      window.clearInterval(id); 
      reject(e); 
     } 
    }, 1000); 
}); 

Es gibt ein paar npm Pakete sind, die diese Anforderung erfüllen, von denen ich promise-waitfor die am besten gefällt. Es ist 38 Zeilen lang und macht den Job.

var myPromise = waitFor(() => { 
    if(conditionA) return true; 
    if(conditionB) throw new Error("conditionB!"); 
    return false; 
}); 
+0

Können Sie mir erklären, wie dies erreicht würde, wenn (conditionA) ein Versprechen ist? Ich kann der Versprechens-Kette niemals entkommen, um ein einfaches 'Wahres' oder 'Falsches' in Wartestellung zu bringen. – NZHammer

+1

Fühlen Sie sich frei, eine separate Frage hinzuzufügen, wenn 'conditionA' ein Versprechen ist. Wahrscheinlich beinhaltet die Lösung 'Promise.race'. –

+0

Ich habe gelesen, dass, wenn Ihre Umfrage dauert länger als Ihre setInverval, wird es Warteschlange erstellen. Wenn es fertig ist, muss es die Warteschlange verarbeiten. Und es ist besser, mit setTimeout und recursion ein anderes setTimeout zu starten. – TamusJRoyce

Verwandte Themen