petkaantonov / bluebird

:bird: :zap: Bluebird is a full featured promise library with unmatched performance.
http://bluebirdjs.com
MIT License
20.45k stars 2.34k forks source link

3.0 cancellation overhaul #415

Closed petkaantonov closed 8 years ago

petkaantonov commented 9 years ago

The current cancellation seems to be the most problematic feature due to some annoying limits in the design:

Since all consumers and producers must be trusted/"your code", there is no reason to enforce that cancellable promises are single-consumer or create new primitives.

Edit: The below design has been scratched, see https://github.com/petkaantonov/bluebird/issues/415#issuecomment-73242358

In the new cancellation you would register the callback while marking the promise cancellable:

promise.cancellable(function onCancel(reason) {

});

This returns a new cancellable promise (unlike right now which just mutates existing promise which causes a lot of headache internally) and the flag will automatically propagate to all derived promises. However, the reference to the onCancel callback will only be held by the new promise created by .cancellable(). Calling .cancel() on a cancellable promise will keep propagating to cancellable parents and calling their onCancel callbacks.

The onCancel callback will receive the cancellation reason as its only argument (the default is a CancellationError instance).

From the callback it's possible to decide the fate of the promise:

(However I guess 99.99% of the time you want throw reason, so this flexibility adds a lot of inconvenience?)

Bad (should use .timeout() for this) example of usage:

function delay(value, time) {
    var timerId;
    return new Promise(function(resolve, reject) {
        timerId = setTimeout(function() {
            resolve(value);
        }, time || value);
    }).cancellable(function(reason) {
        clearTimeout(timerId);
        throw reason;
    });
}

var after500ms = delay(500).catch(CancellationError, function(e) {
    console.log("Your request took too long");
});
delay(250).then(function() {
    after500ms.cancel();
});

petkaantonov commented 8 years ago

I just left the docs partially undone because otherwise 3.0 would never be published :D