Domanda

I have a bluebird promise which can be cancelled. When cancelled, I have to do some work to neatly abort the running task. A task can be cancelled in two ways: via promise.cancel() or promise.timeout(delay).

In order to be able to neatly abort the task when cancelled or timed out, I have to catch CancellationErrors and TimeoutErrors. Catching a CancellationError works, but for some reason I can't catch a TimeoutError:

var Promise = require('bluebird');

function task() {
  return new Promise(function (resolve, reject) {
        // ... a long running task ...
      })
      .cancellable()
      .catch(Promise.CancellationError, function(error) {
        // ... must neatly abort the task ...
        console.log('Task cancelled', error);
      })
      .catch(Promise.TimeoutError, function(error) {
        // ... must neatly abort the task ...
        console.log('Task timed out', error);
      });
}

var promise = task();

//promise.cancel(); // this works fine, CancellationError is caught

promise.timeout(1000); // PROBLEM: this TimeoutError isn't caught!

How can I catch timeout errors before a timeout is set?

È stato utile?

Soluzione

when you cancel a promise, the cancellation first bubbles to its parents as long as a parents are found that are still cancellable, this is very different from normal rejection which only propagates to children.

.timeout does a simple normal rejection, it doesn't do cancellation, so that's why it's not possible to do it like this.

You can either cancel after a delay:

var promise = task();
Promise.delay(1000).then(function() { promise.cancel(); });

or set the timeout in the task function:

var promise = task(1000);

function task(timeout) {
  return new Promise(function (resolve, reject) {
        // ... a long running task ...
      })
      .timeout(timeout)
      .cancellable()
      .catch(Promise.CancellationError, function(error) {
        // ... must neatly abort the task ...
        console.log('Task cancelled', error);
      })
      .catch(Promise.TimeoutError, function(error) {
        // ... must neatly abort the task ...
        console.log('Task timed out', error);
      });
}

You can also create a method like:

Promise.prototype.cancelAfter = function(ms) {
  var self = this;
  setTimeout(function() {
    self.cancel();
  }, ms);
  return this;
};

Then

function task() {
  return new Promise(function (resolve, reject) {
        // ... a long running task ...
      })
      .cancellable()
      .catch(Promise.CancellationError, function(error) {
        // ... must neatly abort the task ...
        console.log('Task cancelled', error);
      })
}

var promise = task();

// Since it's a cancellation, it will propagate upwards so you can
// clean up in the task function
promise.cancelAfter(1000);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top