promise cancellation still firing fulfill function

2019-07-21 01:07发布

问题:

This is my code:

var promiseResult =  new BBpromise(function(resolve, reject){
    console.log(1)
    // some actions
    setTimeout(function(){
        resolve();
    }, 2000);
}).cancellable().catch(BBpromise.CancellationError, function(e){
    console.log(e);
});

promiseResult.then(function(){
    console.log('AYYYY');
});
promiseResult.cancel(new BBpromise.CancellationError()).then(function(s){
    console.log('canceled ?');
});

And I'm getting the following output:

BTW.. the output seems to be immediate. Seems like if just jump that resolve.

1
{ [CancellationError: cancellation error] __stackCleaned__: true }
AYYYY
cancelled ?

It says.. "stactCleaned: true" so I guess that means that all the fulfil functions were cleaned. But seems I'm wrong

So my questions:

  • why when I call to cancel(), in my output I see 'AYYYY' if the promise was cancelled.
  • What's exactly doing cancel in here? what is cancel actually doing in this case?
  • Is there a way to cancel the execution of the content of a promise or the propagation of the promise?

回答1:

why when I call to cancel(), in my output I see 'AYYYY' if the promise was cancelled.

This is the usual behavior of .catch().

With catch(), you are catching the cancellation error and this produces a new promise that is resolved with the value undefined (because you're not returning anything from the .catch() handler).

So the function you provide to then is called just fine.

What is cancel actually doing in this case?

From the Bluebird documentation:

Cancelling a promise propagates to the farthest cancellable ancestor of the target promise that is still pending, and rejects that promise with the given reason, or CancellationError by default.

It is travelling up the promise chain and rejecting that first promise that you created (and which you marked as .cancellable()). .cancel() rejects at most a single promise, not an entire chain.

Is there a way to cancel the execution of the content of a promise or the propagation of the promise?

You can't cancel the execution of code that is already running, which is the case for the code in the function that you're passing to the Promise constructor.

You can cancel the execution of handlers further down the promise chain if the resolution hasn't propagated there yet.

You can cancel the propagation of a promise. You are doing precisely that. But if you catch the cancellation and then chain anything onto that catch, you begin the promise chain anew.

Perhaps this would be a bit illuminating:

var promiseResult =  new Promise(function(resolve, reject){
    console.log(1)
    setTimeout(function(){
        resolve("1");
    }, 2000);
}).cancellable().then(function () {
    console.log("this is never called");
    return 2;
}).catch(Promise.CancellationError, function(e){
    console.log(e);
    return 3;
});

promiseResult.then(function(d){
    console.log("got the value " + d);
    return 4;
});
promiseResult.cancel(new Promise.CancellationError()).then(function(s){
    console.log("and I got the value " + s);
    return 5;
});

The output is:

1
CancellationError: ...
got the value 3
and I got the value 3

As you can see, the original promise is cancelled, so the "this is never called" part is never called. You have catch and then calls that resume the chain further down.