2016-08-05 9 views
5

Inhaltsübersicht: poll() Funktionen mit Rückrufen sind verfügbar; Ich habe keine nativen Versprechungen gefunden. Ich habe versucht, einige ohne Erfolg anzupassen. Das Problem, das ich noch nicht gelöst habe, ist, dass, wenn die erste Instanz der von setTimeout aufgerufenen Funktion ohne Rückkehr endet, die .then(), die darauf wartet, die Beendigung als false und reject() sieht. then() beendet und hört nicht auf spätere Rückgaben.Wie kann ich `.then()` lange genug am Leben halten, um eine Polling-Funktion mit nativen Versprechungen zu erhalten?

Frage: Wie am besten helfen, die Funktion bleiben für spätere Rücksendungen mit resolve() oder reject()?

Der Rest dieses Beitrags ist Detail. Lesen Sie, was hilft.

Verfügbare Pollfunktionen: Ich mag (https://stackoverflow.com/users/1249219/om-shankar) Om Shankars Antwort in Calling a function every 60 seconds. David Walshs Umfrage() ist sehr ähnlich (um https://davidwalsh.name/essential-javascript-functions). Beide verwenden Rückrufe und funktionieren gut. Ich fand poll in javascript , die eine poll() mit bluebird-only verspricht.

Hier ist mein Versuch, mit nativen Versprechen zu implementieren.

/** 
* poll - checks repeatedly whether a condition exists. When the condition 
* exists, returns a resolved standard promise. When it has checked 
* long enough, returns a rejected standard promise. 
* @param {function} fn - a caller-supplied synchronous function that 
* detects a condition in the environment. Returns true if the 
* condition exists; otherwise false. 
* @param {number} timeout - maximum number of milliseconds 
* the caller wants to check param fn(); 
* reject() the promise at the expiration of param timeout. 
* @param {number} interval - minimum number of milliseconds between 
* calls to param fn(); resolve() the promise when param fn() first 
* reports true. 
* @return {promise} - resolved when param fn() returns true; 
* rejected if param timeout expires without param fn() returning true 
*/ 
function poll(fn, timeout, interval) { 
    let endTime = Number(new Date()) + (timeout || 2000) 
    interval = interval || 250 
    return Promise.resolve  *2 
    .then(() => {  *3 
    (function p(fn, endTime, interval) { 
     if (fn()) { return Promise.resolve("Condition is satisfied.") } *4 
     else { 
     if (Number(new Date()) <= endTime) {)  *5 
      window.setTimout(p, interval, fn, endTime, interval) *6 
     } 
     else { 
      return Promise.reject("Past endTime; condition not satisfied") 
     } 
     } 
    }())  *7 
    })  *8 
} 

Erwartete Nutzung:

function waitIsOver() { return (<desired condition exists>) } 
poll(waitIsOver, 2000, 250)  *1 

Die Art, wie ich denke, das läuft (mich bitte korrigieren, wenn ich falsch liege): Nach dem Aufruf von poll() bei * 1, wir ein anhängigen Versprechen schnell wieder bei * 2, so dass poll() weiß warten. Dann nennen wir das Versprechen then() Funktion bei * 3. Die Funktion p() startet. Wenn fn() (bekannt außerhalb p() als waitIsOver()) True bei * 4 zurückgibt, sind wir gut: Wir geben resolve() und poll() um * 1 erhält das abgelegte Versprechen, das es sucht.

Dann wird das Schlimme: Wenn fn() false zurück an * 4 und wir sind innerhalb endTime bei * 5 (was wahrscheinlich ist, das erste Gespräch unwahrscheinlich ist, nach endTime auftreten), verwenden wir setTimeout() an * 6 JS fragen eine Notiz im Stapel zu machen, um eine weitere p() nach interval Zeit instanziieren. Danach endet die erste Instanz von p() bei * 7. An * 8, then() weiß, dass p() beendet wurde, ohne etwas zurückzugeben und interpretiert die Bedingung als false und reject() zurückgeben; Mit reject() ist das Versprechen erledigt und kann sich nie ändern. Nach Ablauf von interval wird jedoch eine Nachfolgerinstanz von p() ausgelöst. Alles, was es zurückgibt, ist verloren; Das Versprechen ist erfüllt und then() wurde beendet, nachdem die Ausführung auf einem unerwünschten Pfad gesendet wurde.

How do I convert an existing callback API to promises? empfiehlt einen Ansatz mit einem Konstruktor Versprechen, resolve()callback() Aufruf und reject()errback aufrufen. Ich habe versucht, die Technik, aber ich stieß auf das gleiche Problem der then() Funktion endet, bevor ich es will. Ich habe noch nicht herausgefunden, wie man then() als Patient in Wartestellung als Callback-Funktion macht.

Das setzt die Frage auf.Wieder:

Frage: Wie am besten helfen, die Funktion bleiben für spätere Rückgaben von resolve() oder reject()?

+0

Dies ist, was wie eine übermäßig komplizierte Frage aussieht. Können Sie nur zwei Absätze nehmen und beschreiben, was Sie ohne Rücksicht auf Ihre aktuelle (und fehlerhafte) Anstrengung erreichen wollen. Ich denke, eine Lösung ist viel einfacher, als du es machst, aber dein Code ist so kompliziert, dass ich den Wald nicht von den Bäumen sehen kann, um genau zu verstehen, was du zu erreichen versuchst. – jfriend00

+0

Ich hoffe auch, Sie wissen, dass Versprechen One-Shot-Geräte sind.Sie geben genau einmal einen Wert oder einen Fehler zurück, so dass sie nicht selbst für die Abfrageergebnisse arbeiten. Sie können in Umfragen verwendet werden, aber nicht für sich selbst. – jfriend00

+0

Ich versuche eine 'poll()' Funktion mit nativen Versprechungen zu schreiben; Ich werde den Titel bearbeiten. Vielleicht besteht ein Teil der Motivation darin, mehr über einheimische Versprechen zu erfahren. Ich verstehe den One-Shot-Charakter von Versprechen. Haben Sie ein Beispiel für etwas, das ich verwenden kann, um ".then()" während einer Umfragezeit offen zu halten? – BaldEagle

Antwort

4

Wie man am besten die .then() Funktion Stick helfen, um für eine spätere Rückkehr von resolve() oder ablehnen()

Ein Handler wird aufgerufen, wenn das zugrunde liegende Versprechen aufgelöst oder zurückgewiesen wird. Es wird nie vorher genannt. Wenn Sie also verzögern möchten, wenn der Handler aufgerufen wird, verzögern Sie das Auflösen oder Ablehnen des zugrunde liegenden Versprechens bis zum richtigen Zeitpunkt.

Wie Sie aus meinen Kommentaren entnehmen können, ist es schwer zu sagen, was genau Sie erreichen möchten, weil Sie nicht nur ein einfaches Ziel beschreiben, das Sie erreichen möchten.

Angesichts dessen, hier ist meine Vermutung, was Sie erreichen möchten. Eine klare Frage hätte in wenigen Minuten eine Antwort erhalten.

Wenn Sie nur wiederholt Ihre Funktion abzufragen, bis er einen truthy Wert zurückgibt, oder bis die Timeout-Zeit trifft, können Sie diese mit Standard-ES6 Promies tun:

function poll(fn, timeout, interval) { 
    return new Promise(function(resolve, reject) { 
     // set timeout timer 
     var timeoutTimer = setTimeout(function() { 
      clearInterval(intervalTimer); 
      reject("Past endTime; condition not satisfied"); 
     }, timeout); 

     // set polling timer 
     var intervalTimer = setInterval(function() { 
      if (fn()) { 
       clearTimeout(timeoutTimer); 
       clearInterval(intervalTimer); 
       resolve("Condition is satisfied"); 
      } 
     }, interval); 
    }); 
} 

poll(yourFounction, 5000, 100).then(function(result) { 
    // succeeded here 
}).catch(function(err) { 
    // timed out here 
}) 

Oder mit der Drossel Versprechen Bibliothek, Sie können ihre .timeout() Methode, dies zu tun verwenden:

function poll(fn, timeout, interval) { 
    return new Promise(function(resolve, reject) { 
     // set polling timer 
     var intervalTimer = setInterval(function() { 
      if (fn()) { 
       clearInterval(intervalTimer); 
       resolve("Condition is satisfied"); 
      } 
     }, interval); 
    }).timeout(timeout, "Past endTime; condition not satisfied"); 
} 

poll(yourFounction, 5000, 100).then(function(result) { 
    // succeeded here 
}).catch(function(err) { 
    // timed out here 
}) 

Beachten Sie, dass diese beiden Systeme ein Versprechen zurückzukehren und dann, wenn die poll() Funktion fertig ist, sie entweder Anruf Vorsatz oder ablehnen zu diesen neuen Versprechen und das wird dann Trigger alle .then() Handler aufgerufen werden.


P.S. Ich sollte hinzufügen, dass dies alles davon ausgeht, dass Ihre fn() eine synchrone Funktion ist, die einen truthigen oder falschen Wert zurückgibt (was Ihr Code zu vermuten scheint). Wenn Ihre fn() tatsächlich eine asynchrone Funktion mit einem Rückruf oder einer Zusage ist, dann muss dies in das Design einkalkuliert werden. Sie müssten uns zeigen, was die Aufrufkonvention für die Funktion ist, bevor wir Code schreiben könnten, um diesen korrekt zu verwenden.

+0

Ich stimme Ihrem Beitrag zu. Es ist ziemlich viel eine Wiederholung meines. Es ist ein ziemlich wackeliger Anwendungsfall. Ich kann mir keinen Anwendungsfall für diese Art von Problem vorstellen. Die meisten Abfragen werden über die Leitung durchgeführt und werden asynchron sein. Ich bin wirklich neugierig zu hören, was er benutzt Fall ist das. –

+0

Das ist schöner und eleganter Code. Es ist für mein gegenwärtiges Projekt perfekt und ich behalte es in meiner "gehe zu" Codekollektion. Bezüglich der Frage: Ich habe gehört, "Es ist nicht genug zu schreiben damit du verstanden wirst. Du musst schreiben, damit du nicht missverstanden werden kannst! "Ich bedauere, dass du bei letzterem für dich versagt hast. – BaldEagle

+0

@BaldEagle - Für das nächste Mal lies das [XY-Problem] (http://meta.stackexchange.com/questions/66377/) Was-ist-das-xy-Problem) Hier beschreibt die Frage Probleme mit Ihrer Lösungsansätze, anstatt zuerst das Ziel/die Spezifikation für das, was Sie erreichen wollen, zu beschreiben, was es für uns schwierig macht, Ihnen die beste Lösung anzubieten Sie wollen auch sehen, was Sie ausprobiert haben, also ist es gut, dass Sie das eingeschlossen haben, aber wenn es zu weit weg ist, dann beschreibt es nicht, was Sie eigentlich gut genug für uns tun wollen bieten eine echte Lösung – jfriend00

2

Da Sie gesagt haben, dass Sie Polling-Funktionen gefunden haben, die Rückrufe haben, läuft das im Grunde auf "Wie mache ich etwas Promis?"

Verwenden BluebirdJS ‚s Promisify:

var poleYouFoundThatHasCallback = require('somePollLibrary'); 
var Promise = require('bluebird'); 
var poll = Promise.Promisify(poleYouFoundThatHasCallback); 

poll.then((res) => { 
//dostuff with res here 

}).catch(err => console.log(err)) 

Sie auch ein Timeout auf es für scheißt und kichert werfen.

Hier ist und beispielsweise aus der docs:

var Promise = require("bluebird"); 
var fs = Promise.promisifyAll(require('fs')); 
fs.readFileAsync("huge-file.txt").timeout(100).then(function(fileContents) { 

}).catch(Promise.TimeoutError, function(e) { 
    console.log("could not read file within 100ms"); 
}); 
+0

Danke. Noch näher: "Wie promote ich eine Umfragefunktion mit Standardversprechen?" – BaldEagle

+0

Gute Bluebird-Lösung. Vielen Dank. Außerdem demonstriert Ihr Code eine Technik, eine Sammlung von "Gehe zu" -Funktionen (Poll() ist eine von mir) in separate kleine Module aufzuteilen. Gute Technik. Danke auch dafür. – BaldEagle

Verwandte Themen