w3schools style promises promesas ejemplos change attribute anidadas javascript promise q

javascript - style - Promesas: Repita la operación hasta que tenga éxito?



title css (5)

Quiero realizar una operación repetidamente, con un tiempo de espera cada vez mayor entre cada operación, hasta que tenga éxito o transcurra una cierta cantidad de tiempo. ¿Cómo estructuro esto con promesas en Q?


  1. Asigne una variable booleana para "todo el tiempo de espera del proceso".
  2. Llame a setTimeout de la ventana para hacer que la variable sea "falsa" después de que "todo el tiempo de espera del proceso".
  3. Operación promesa de llamada con un tiempo de espera.
  4. Si tiene éxito no hay problema.
  5. Si falla: en el controlador de errores de la promesa, vuelva a llamar a la función de promesa con un tiempo de espera incrementado si la variable booleana es verdadera.

Algo como esto:

var goOn= true; setTimeout(function () { goOn= false; }, 30000); // 30 seconds -- all process timeout var timeout = 1000; // 1 second (function () { var helperFunction = function () { callAsyncFunc().then(function () { // success... }, function () { // fail if (goOn) { timeout += 1000; // increase timeout 1 second helperFunction(); } }).timeout(timeout); } })();


Aquí hay un ejemplo de cómo abordaría esto, con algunas funciones de ayuda. Tenga en cuenta que el ''maxTimeout'' es la parte más complicada porque tiene que competir en dos estados.

// Helper delay function to wait a specific amount of time. function delay(time){ return new Promise(function(resolve){ setTimeout(resolve, time); }); } // A function to just keep retrying forever. function runFunctionWithRetries(func, initialTimeout, increment){ return func().catch(function(err){ return delay(initialTimeout).then(function(){ return runFunctionWithRetries( func, initialTimeout + increment, increment); }); }); } // Helper to retry a function, with incrementing and a max timeout. function runFunctionWithRetriesAndMaxTimeout( func, initialTimeout, increment, maxTimeout){ var overallTimeout = delay(maxTimeout).then(function(){ // Reset the function so that it will succeed and no // longer keep retrying. func = function(){ return Promise.resolve() }; throw new Error(''Function hit the maximum timeout''); }); // Keep trying to execute ''func'' forever. var operation = runFunctionWithRetries(function(){ return func(); }, initialTimeout, increment); // Wait for either the retries to succeed, or the timeout to be hit. return Promise.race([operation, overallTimeout]); }

Luego, para usar estos ayudantes, harías algo como esto:

// Your function that creates a promise for your task. function doSomething(){ return new Promise(...); } runFunctionWithRetriesAndMaxTimeout(function(){ return doSomething(); }, 1000 /* start at 1s per try */, 500 /* inc by .5s */, 30000 /* max 30s */);


Creo que no puede hacerlo a nivel de promesa: una promesa no es una operación, sino que es un valor que llegará en el futuro, por lo que no puede definir una función escrita Promise -> Promise que lo logrará .

Necesitaría bajar un nivel y definir una función escrita Operation -> Promise donde se escribe la Operación () -> Promise . Supongo que la operación no toma ningún parámetro; puede aplicarlos parcialmente de antemano.

Este es un enfoque recursivo que duplica el tiempo de espera en cada ejecución:

function RepeatUntilSuccess(operation, timeout) { var deferred = Q.defer(); operation().then(function success(value) { deferred.resolve(value); }, function error(reason) { Q.delay(timeout .then(function() { return RepeatUntilSuccess(operation, timeout*2); }).done(function(value) { deferred.resolve(value); }); }); return deferred.promise; }

Demostración: http://jsfiddle.net/0dmzt53p/


Hice lo siguiente con Promises / A + (que debería estar bien con Q)

function delayAsync(timeMs) { return new Promise(function(resolve){ setTimeout(resolve, timeMs); }); } //use an IIFE so we can have a private scope //to capture some state (function(){ var a; var interval = 1000; a = function(){ return doSomethingAsync() .then(function(success){ if(success) { return true; } return delayAsync(interval) .then(function(){ interval *= 2; }) .then(a()); }); }; a(); })();

Estoy seguro de que podrías descubrir cómo rescatarte después de un tiempo de espera máximo.


Todas las respuestas aquí son realmente complicadas en mi opinión. Kos tiene la idea correcta, pero puedes acortar el código escribiendo un código de promesa más idiomático:

function retry(operation, delay) { return operation().catch(function(reason) { return Q.delay(delay).then(retry.bind(null, operation, delay * 2)); }); }

Y con comentarios:

function retry(operation, delay) { return operation(). // run the operation catch(function(reason) { // if it fails return Q.delay(delay). // delay // retry with more time then(retry.bind(null, operation, delay * 2)); }); }

Si desea agotar el tiempo después de un cierto tiempo (digamos 10 segundos, simplemente puede hacer:

var promise = retry(operation, 1000).timeout(10000);

Esa funcionalidad está incorporada en Q, no es necesario reinventarla :)