Skip to content

Instantly share code, notes, and snippets.

@novemberborn
Last active December 10, 2015 07:08
Show Gist options
  • Save novemberborn/4399269 to your computer and use it in GitHub Desktop.
Save novemberborn/4399269 to your computer and use it in GitHub Desktop.
Cancelation/A+ Draft A

Cancelation/A+

This proposal specifies how cancelation is triggered, handled and propagated in a Promises/A+ promise library.

Terminology

In addition to the terminology from Promises/A+ we use the following:

  1. OperationCanceled is an error used to reject canceled promises.
  2. "direct cancelation" is when a promise is canceled by the consumer of the promise calling 'cancel'.
  3. "indirect cancelation" is when a promise is canceled as the result of another promise that was waiting on it being directly or indirectly canceled.

Requirements

The OperationCanceled Error

When a promise is directly canceled it is rejected with an OperationCanceled error. This error must obey the following points:

  1. It must be an instance of error (error instanceof Error === true).
  2. It must have a name property with value "OperationCanceled".

The cancel Method

When the cancel method is called on a promise it is directly canceled. The cancel method accepts two arguments:

promise.cancel(data, message);
  1. The promise must be rejected with an OperationCanceled error.
  2. Both data and message are optional:
  3. If data is undefined it should be ignored.
  4. If message is not a string it should default to "Operation Canceled".
  5. If data is not undefined it is set as the data property of the OperationCanceled error.
  6. If message is a string it is used as the message property of the OperationCanceled error.
  7. The promise must change its state and propagate its cancelation as if propagateCancel had been called, and return the result of the propagation (meaning a promise is returned) [3.1].

The propagateCancel Method

The propagateCancel method is intended only to be called by this and other promises, it is not for external use.

When propagateCancel is called, the promise transitions into an extra canceled state. This does not trigger any events. It does however mean that the promise can never be resolved (i.e. it never leaves the canceled state).

  1. If the promise is waiting on another promise to complete it may call propagateCancel on the promise it is waiting for.
  2. It must return a promise for the result of calling the onCanceled callback attached to the resolver.
  3. If the promise is fulfilled, its value must be undefined.
  4. If no onCanceled callback is available, or the resolver is unable to cancel, it must still return a promise, fulfilled with undefined.
  5. If the onCanceled callback throws an exception, the promise must be rejected with that exception as its reason.

In most cases it should call propagateCancel on the promise it's waiting for. The exception is if the promise has been in some way 'forked', when it may choose not to in an implementation specific way.

The onCanceled Callback

An onCanceled callback can be added to the resolver. The onCanceled callback accepts one argument:

resolver.onCanceled = function(resolver){
  
};
  1. When a promise is canceled (directly or indirectly) the resolver for that promise must invoke its onCanceled callback.
  2. The onCanceled callback must be ignored if it's not a function.
  3. The first argument to the callback must be the resolver itself.
  4. The expected this value inside the callback is left unspecified.
  5. The resolver may remove the callback once it's no longer pending.

Propagating Cancelations To Resolvers

  1. A resolver must ignore propagated cancelations if there are other promises depending on it.
  2. Conversely, a resolver can only be indirectly canceled if that cancelation comes from the only promise that depends on it.

Calling then On Canceled Promises

  1. If the promise was directly canceled, the returned promise must be rejected with the OperationCanceled error that resulted from canceling the promise.
  2. If the promise was indirectly canceled, the returned promise must be rejected with a generic OperationCanceled error, with default values for data and message properties.

Notes

  1. Implementations may call propagateCancel directly from cancel, or not at all, as long as the end result is equivalent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment