promises-aplus / cancellation-spec

Discussion and drafts of a possible promise cancellation spec.
24 stars 5 forks source link

Draft B #5

Open novemberborn opened 11 years ago

novemberborn commented 11 years ago

See https://gist.github.com/4407774 for the spec. Work-in-progress implementation at https://github.com/novemberborn/legendary/tree/cancelation-draft-b.

ForbesLindesay commented 11 years ago

If options is not null or of type object its properties, except for name, are copied onto the OperationCanceled error.

should read:

If options is of type object its properties, except for name, are copied onto the OperationCanceled error.

ForbesLindesay commented 11 years ago

Resolvers may directly cancel themselves if the only derived and pending promise is canceled (directly or indirectly).

should read:

Resolvers may directly cancel themselves if all derived promises are cancelled (directly or indirectly).

ForbesLindesay commented 11 years ago

Good points

Bad points

Solution

One solution to the first point is to require an onCancelled method, leading to the signature:

promise.then(onFulfilled, onRejected, onProgress, onCancelled)

onCancelled would then be called whenever a promise is cancelled either directly or indirectly. If the promise was cancelled directly, it is called instead of the onRejected handler if it's present.

When you wire up one promise, to another (resolver, promise) pair you then need to do something like:

promiseA.then(resolverB.fulfill, resolverB.reject. resolverB.progress);

promiseB.then(null, null, null, promiseA.cancel);

which is hideous, we need to sort this.

ForbesLindesay commented 11 years ago

In short, I don't think removing .propagateCancel like this actually works.

novemberborn commented 11 years ago

The trick I'm using for propagating cancelation is that with:

var aToB = promiseA.then(resolverB.fulfill, resolverB.reject, resolverB.progress);

When resolverB is canceled, it can propagate by canceling aToB. The implementation can then decide how to propagate that cancelation internally.

ForbesLindesay commented 11 years ago

OK, that's fine, since the resolver gets cancelled for direct and indirect cancellation, that should work, along the lines of:

var aToB = promiseA.then(resolverB.fulfill, resolverB.reject, resolverB.progress);
resolverB.onCancel(aToB.cancel());

Since B has already been directly cancelled, it doesn't matter if we call resolverB.reject an extra time. The internal workings of then must still be considered properly:

function then(cb, eb) {
  let {promiseB, resolverB} = defer();
  resolverB.onCancel(resolverA.cancel); //note here that we **indirectly** cancel ourselves
  //Normal then method stuff goes here
  return promiseB;
}