2022-05-31 15:38:40 +00:00
|
|
|
/**
|
|
|
|
* Converts a function type returning a `Promise` to a function type returning `void`.
|
|
|
|
*/
|
|
|
|
export type NoAwait<F extends (...args: unknown[]) => Promise<unknown>> =
|
|
|
|
(...args: Parameters<F>) => void;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Signals that the argument returns a `Promise` that is intentionally not being awaited.
|
|
|
|
*/
|
|
|
|
export function noAwait<F extends (...args: unknown[]) => Promise<unknown>>(f: F): NoAwait<F> {
|
|
|
|
return f as NoAwait<F>;
|
|
|
|
}
|
2022-06-05 17:57:04 +00:00
|
|
|
|
2022-06-12 16:05:01 +00:00
|
|
|
/**
|
Interruptable spawn (#132)
* Add `spawn` as a way of calling promise-returning blocks
This change adds `spawn` which takes a no-argument, promise-returning
function, calls it, and returns `void`. This makes it easy to call
async blocks from `useEffect` and other places that don't take async
functions, but also makes such calls explicit.
* Adds interruptability to `spawn`
Now, the task function passed to `spawn` can take an `Interrupted`
argument, which is merely a method that returns `true` if the task
should stop doing work. Likewise, `spawn` returns an `Interrupt`
function that causes the `Interrupted` function to return `true`.
* Change to using `AbortController` and `AbortSignal`
Before, `spawn` used functions to interrupt and determine interruption
state. Now, based on feedback from @whscullin, it uses
`AbortController` and `AbortSignal`.
Tests now show how the controller can be used to abort long-running
tasks and API calls in the `spawn`. The also show how signals can be
chained using `addEventListener`.
* Fix `Apple2.tsx`
Forgot to change it to use `AbortController` and `AbortSignal`.
Co-authored-by: Will Scullin <scullin@scullin.com>
2022-06-12 16:06:58 +00:00
|
|
|
* Calls the given `Promise`-returning function, `f`, and does not await
|
|
|
|
* the result. The function `f` is passed an {@link Interrupted} function
|
|
|
|
* that returns `true` if it should stop doing work. `spawn` returns an
|
|
|
|
* {@link Interrupt} function that, when called, causes the `Interrupted`
|
|
|
|
* function to return `true`. This can be used in `useEffect` calls as the
|
|
|
|
* cleanup function.
|
2022-06-12 16:05:01 +00:00
|
|
|
*/
|
Interruptable spawn (#132)
* Add `spawn` as a way of calling promise-returning blocks
This change adds `spawn` which takes a no-argument, promise-returning
function, calls it, and returns `void`. This makes it easy to call
async blocks from `useEffect` and other places that don't take async
functions, but also makes such calls explicit.
* Adds interruptability to `spawn`
Now, the task function passed to `spawn` can take an `Interrupted`
argument, which is merely a method that returns `true` if the task
should stop doing work. Likewise, `spawn` returns an `Interrupt`
function that causes the `Interrupted` function to return `true`.
* Change to using `AbortController` and `AbortSignal`
Before, `spawn` used functions to interrupt and determine interruption
state. Now, based on feedback from @whscullin, it uses
`AbortController` and `AbortSignal`.
Tests now show how the controller can be used to abort long-running
tasks and API calls in the `spawn`. The also show how signals can be
chained using `addEventListener`.
* Fix `Apple2.tsx`
Forgot to change it to use `AbortController` and `AbortSignal`.
Co-authored-by: Will Scullin <scullin@scullin.com>
2022-06-12 16:06:58 +00:00
|
|
|
export function spawn(f: (abortSignal: AbortSignal) => Promise<unknown>): AbortController {
|
|
|
|
const abortController = new AbortController();
|
|
|
|
noAwait(f)(abortController.signal);
|
|
|
|
return abortController;
|
2022-06-12 16:05:01 +00:00
|
|
|
}
|
|
|
|
|
2022-06-05 17:57:04 +00:00
|
|
|
/**
|
|
|
|
* Utility class that allows a promise to be passed to a
|
|
|
|
* service to be resolved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
export class Ready {
|
|
|
|
onError: (value?: unknown) => void;
|
|
|
|
onReady: (value?: unknown) => void;
|
|
|
|
|
|
|
|
ready: Promise<unknown>;
|
|
|
|
|
|
|
|
constructor(private errorHandler = console.error) {
|
|
|
|
this.ready = new Promise((resolve, reject) => {
|
|
|
|
this.onReady = resolve;
|
|
|
|
this.onError = reject;
|
|
|
|
}).catch(this.errorHandler);
|
|
|
|
}
|
|
|
|
}
|