2015-10-19 9 views
9

Sto scrivendo del codice per eseguire il polling per una risorsa ogni N ms che dovrebbe scadere dopo M secondi. Voglio che tutto sia promesso basandomi il più possibile su Bluebird. La soluzione che ho trovato finora utilizza l'intervallo del nodo, le promesse bluebird cancellabili e la funzione di timeout di bluebird.Che cosa è un buon modello per "intervallo con timeout" utilizzando Promises

Mi chiedo se c'è un modo migliore per programmare gli intervalli con bluebird e promesse in generale? Principalmente assicurandosi che l'intervallo si fermi al punto e non continui mai indefinitamente.

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); 
    }); 

uscita:

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

risposta

5

vorrei fare qualcosa di simile -

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() 
} 

Anche essere consapevoli di Promise constructor anti-pattern

+1

Nice. Come completeresti l'intervallo? Sembra l'unica via d'uscita se si genera un errore. So che il costruttore Promise è un anti-pattern, ma in questo caso sembrava adattarsi (lo stesso vale per gli eventi + Promises ma questo è un altro argomento). – Chris911

+0

Ok ora capisco la tua domanda. Controlla la mia modifica. – vinayr

+0

Sì, questo funziona. Grazie e risposta accettata. – Chris911

1

Rene Wooller rende davvero un buon punto:

Attenzione: purtroppo, la ricorsione in javascript come questo finirà per saturare lo stack di chiamate e il risultato in fuori eccezioni di memoria

Anche se non fa eccezione, questo è sprecato spazio, e il rischio di un'eccezione potrebbe incoraggiare un ritardo nel polling troppo lungo.

credo che questo sia abbastanza importante da preferire setInterval:

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); 
}); 

ci sono un paio di pacchetti di NPM che affrontano questa esigenza, di cui mi piace promise-waitfor il migliore. È lungo 38 linee e fa il lavoro.

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

Puoi spiegarmi come questo si realizzerebbe se (conditionA) è una promessa? Non posso mai sfuggire alla catena delle promesse per restituire un semplice 'vero' o 'falso' in waitFor(). – NZHammer

+1

Sentiti libero di aggiungere una domanda separata per quando 'conditionA' è una promessa. Probabilmente la soluzione coinvolge 'Promise.race'. –

+0

Ho letto che se il tuo sondaggio richiede più tempo per essere eseguito rispetto al tuo setinverval, verrà creato in coda. Quindi, al termine, deve elaborare la coda. E che è meglio usare setTimeout e ricorsione per dare il via ad un altro setTimeout. – TamusJRoyce

Problemi correlati