Search code examples
node.jsbluebird

What is a good pattern for "interval with timeout" using Promises


I'm writing some code to do polling for a resource every N ms which should timeout after M seconds. I want the whole thing to be promise based using Bluebird as much as possible. The solution I've come up with so far uses node's interval, cancellable bluebird promises and bluebird's timeout function.

I'm wondering if there's a better way to do timing out intervals with bluebird and promises in general? Mostly by making sure the interval stops at the point and never continues indefinitely.

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

Output:

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

Solution

  • I would do something like this -

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

    Also be aware of Promise constructor anti-pattern