Created
October 8, 2019 07:03
-
-
Save joelbinn/1d9615cc13e7ad5151673683835ce892 to your computer and use it in GitHub Desktop.
A typescript implementation of a cancellable promise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { CancellablePromise } from './cancellable-promise' | |
describe('CancellablePromise', () => { | |
describe('when cancelling', () => { | |
it( 'should reject with information of this', async () => { | |
const p: CancellablePromise<string> = new CancellablePromise(new Promise<string>(resolve => undefined)) | |
p.cancel() | |
await expect(p).rejects.toEqual({wasCancelled: true}) | |
}) | |
}) | |
describe('when original promise resolves', () => { | |
it('should resolve with that result', async () => { | |
const p: CancellablePromise<string> = new CancellablePromise(Promise.resolve('resultat')) | |
await expect(p).resolves.toEqual('resultat') | |
}) | |
}) | |
describe('when original promise rejects', () => { | |
let p: CancellablePromise<string> | |
beforeEach(() => { | |
p = new CancellablePromise(Promise.reject('fel')) | |
}) | |
it('should resolve with that error reason', async () => { | |
await expect(p).rejects.toEqual('fel') | |
}) | |
it('should invoke catch', async () => { | |
let error = undefined | |
await p.catch(e => error = e) | |
expect(error).toEqual('fel') | |
}) | |
}) | |
it('should invoke finally', async () => { | |
const p: CancellablePromise<string> = new CancellablePromise(Promise.resolve('resultat')) | |
let final = undefined | |
await p.finally(() => final = 'klar') | |
expect(final).toEqual('klar') | |
}) | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Error object thrown if the promise is cancelled. | |
*/ | |
export interface Cancellation { | |
wasCancelled: boolean | |
} | |
/** | |
* A promise that can be cancelled (primarily to be used in backend calls). | |
* | |
* When the promise is cancelled it will reject with a Cancellation error. | |
*/ | |
export class CancellablePromise<T> implements Promise<T> { | |
private static seq = 0 | |
readonly id = CancellablePromise.seq++ | |
private readonly promise: Promise<T> | |
private rejectInnerPromise?: (reason?: any) => void | |
private hasFinished = false | |
constructor(orgPromise: Promise<T>) { | |
this.promise = new Promise<T>((resolve, reject) => { | |
this.rejectInnerPromise = reject | |
orgPromise.then( | |
r => resolve(r), | |
e => reject(e) | |
).finally(() => this.hasFinished = true) | |
}) | |
} | |
cancel() { | |
if (!this.hasFinished) { | |
// console.log('Cancel Promise:', this.id) | |
this.rejectInnerPromise && this.rejectInnerPromise({wasCancelled: true}) | |
} | |
} | |
readonly [Symbol.toStringTag]: string | |
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult> { | |
return this.promise.catch(onrejected) | |
} | |
finally(onfinally?: (() => void) | undefined | null): Promise<T> { | |
return this.promise.finally(onfinally) | |
} | |
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2> { | |
return this.promise.then(onfulfilled, onrejected) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment