Skip to content

Commit

Permalink
Add documentation for TokenSource/Token
Browse files Browse the repository at this point in the history
  • Loading branch information
jeskew committed May 23, 2017
1 parent 7f7ed81 commit 028ee7d
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 7 deletions.
4 changes: 2 additions & 2 deletions packages/cancellation-token/__tests__/Token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ describe('Token', () => {
const token = new Token();

expect(token.cancellable).toBe(false);
expect(token.canceled).toBe(false);
expect(token.cancelled).toBe(false);
});

it('should defer cancellation queries to parent token source', () => {
const source = {isCancellationRequested: true};
const token = new Token(<TokenSource>source);

expect(token.canceled).toBe(true);
expect(token.cancelled).toBe(true);
source.isCancellationRequested = false;
expect(token.isCancellationRequested).toBe(false);
});
Expand Down
42 changes: 37 additions & 5 deletions packages/cancellation-token/lib/Token.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,69 @@
import {TokenSource} from './TokenSource';

/**
* @see {TokenSource}
*
* Holders of a Token object may query if the associated operation has been
* cancelled, register cancellation handlers, and conditionally throw an Error
* if the operation has already been cancelled.
*/
export class Token {
/**
* Whether the associated operation may be cancelled at some point in the
* future.
*/
public readonly cancellable: boolean;

/**
* Creates a new Token linked to a provided TokenSource. If no source is
* provided, the Token cannot be cancelled.
*/
constructor(private readonly source?: TokenSource) {
this.cancellable = Boolean(source);
}

get canBeCanceled(): boolean {
/**
* Alias of this.cancellable
*/
get canBeCancelled(): boolean {
return this.cancellable;
}

get canceled(): boolean {
/**
* Whether the associated operation has already been cancelled.
*/
get cancelled(): boolean {
if (this.source) {
return this.source.isCancellationRequested;
}

return false;
}

/**
* Alias of this.canceled
*/
get isCancellationRequested(): boolean {
return this.canceled;
return this.cancelled;
}

/**
* Registers a handler to be invoked when cancellation is requested. If
* cancellation has already been requested, the handler will be invoked on
* the next tick of the event loop.
*/
onCancellationRequested(cb: () => void): void {
if (this.source) {
this.source.registerCancellationHandler(cb);
}
}

/**
* Throws an error if the associated operation has already been cancelled.
*/
throwIfCancellationRequested(reason?: string): void {
if (this.canceled) {
throw new Error(reason);
if (this.cancelled) {
throw new Error(`Operation cancelled${reason ? `: ${reason}` : ''}`);
}
}
}
30 changes: 30 additions & 0 deletions packages/cancellation-token/lib/TokenSource.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
import {Token} from "./Token";

/**
* The AWS SDK uses a TokenSource/Token model to allow for cooperative
* cancellation of asynchronous operations. When initiating such an operation,
* the caller can create a TokenSource and then provide linked tokens to
* subtasks. This allows a single source to signal to multiple consumers that a
* cancellation has been requested without dictating how that cancellation
* should be handled.
*
* Holders of a TokenSource object may create new tokens, register cancellation
* handlers, or declare an operation cancelled (thereby invoking any registered
* handlers).
*/
export class TokenSource {
private _cancellationRequested: boolean = false;
private _invokeAfterCancellation: Array<() => void> = [];

/**
* Whether the operation associated with this TokenSource has been
* cancelled.
*/
get isCancellationRequested(): boolean {
return this._cancellationRequested;
}

/**
* Creates a new Token object linked to this TokenSource (i.e., one that
* will signal cancellation when this source has been cancelled).
*/
get token(): Token {
return new Token(this);
}

/**
* Declares the operation associated with this TokenSource to be cancelled
* and invokes any registered cancellation handlers. The latter may be
* skipped if so desired.
*/
cancel(invokeRegisteredActions: boolean = true): void {
this._cancellationRequested = true;

Expand All @@ -25,6 +50,11 @@ export class TokenSource {
}
}

/**
* Adds a handler to be invoked when cancellation of the associated
* operation has been requested. If cancellation has already been requested,
* the handler will be invoked on the next tick of the event loop.
*/
registerCancellationHandler(handler: () => void): void {
if (this._cancellationRequested) {
setTimeout(handler, 0);
Expand Down

0 comments on commit 028ee7d

Please sign in to comment.