0.2.0 • Published 8 years ago

sn-cancelable v0.2.0

Weekly downloads
4
License
ISC
Repository
github
Last release
8 years ago

cancelable Travis-CI build result

This proposal tries replacing cancellation token from cancelable-promise with cancellation chain object, to achieve more automatic cancellation propagation.

TODO
  • chain keyword may be able to be confused with normal promise then chain.

Differences from cancelable-promise

  • Promise.cancelable(async (chain) => { /* ... */ });
  • promise[@@cancel]

New CancelableChain object is passed to Promise.cancelable input callback. This object can store other promises and cancel them when its underlying promise gets canceled. Its constructor is exposed to make a standalone chain instead of Promise dependant one.

interface CancelableChain {
  constructor(): CancelableChain;

  /*
   * `chain()` stores objects that supports `@@cancel` and call it
   * if cancellation is requested.
   */
  <T>(cancelable: CancelablePromise<T>): Promise<T>;
  (cancelable: Cancelable): Promise<void>;

  cancel(): void; // same as current `cancel` parameter to shorten the parameter list
  
  canceled: boolean; // true when underlying promise is canceled
  tillCanceled: Promise<void>; // resolves when underlying promise gets canceled
  /*
   * throws CancelError when underlying promise gets canceled, otherwise returns nothing
   */
  throwIfCanceled: void;
  
  [[chainedList]]: Cancelable[]; // stored cancelables.
}

// A cancelable is an object that supports Symbol.cancel.
interface Cancelable {
  [@@cancel](): void;
}
interface Promise<T> extends Cancelable {}

Use

function inner() {
  return Promise.cancelable(async (chain) => {
    await a();
    chain.throwIfCanceled();
    await b();
  });
}

function outer() {
  return Promise.cancelable(async (chain) => {
    await chain(inner()); // cancels inner() when parent promise gets canceled
  });
}
function inner() {
  return Promise.cancelable(async (chain) => {
    await a();
    if (!chain.canceled) {
      await b();
    }
  });
}
function inner() {
  return Promise.cancelable(async (chain) => {
    const state = { foo: false }
    chain.tillCanceled.then(() => state.foo = true);
    await c(state);
  });
}

Syntax sugar

A cancelable function has a new chain keyword in its function scope.

cancelable function inner() {
  await a();
  chain.throwIfCanceled(); // chain as keyword, a form like `new.target`
  await b();
}

cancelable function outer() {
  chain inner(); // store inner() promise to cancellation chain
}
cancelable function inner() {
  await a();
  if (!chain.canceled) { // chain as keyword
    await b();
  }
}

Token style to chain style

chain(promise) returns input promise so that promise.then can happen after chaining.

let chain = new CancelableChain();
chain(fetch())
  .then(() => chain(process()));

chain.cancel();

This example with .then() works basically same as the following example.

let chain = new CancelableChain();
chain(fetchAndProcess());

chain.cancel();

cancelable function fetchAndProcess() {
  chain fetch();
  chain process();
}
0.2.0

8 years ago

0.1.7

8 years ago

0.1.6

8 years ago

0.1.5

8 years ago

0.1.4

8 years ago

0.1.3

8 years ago

0.1.2

8 years ago

0.1.1

8 years ago