fcr-core
Version:
Core APIs for building online scenes
54 lines • 1.85 kB
JavaScript
import "core-js/modules/web.dom-exception.stack.js";
import { retryAttempt, to } from '../imports';
/**
* Creates an abortable retry operation that can be cancelled at any time.
*
* The handler function will be retried up to `retriesMax` times if it fails.
* The operation can be cancelled by calling the returned abort function,
* which will cause the promise to reject with an AbortError.
*
* @example
* ```typescript
* const [abort, promise] = abortableRetry(async (signal) => {
* await asyncFunction1();
* // Check if aborted after each async operation
* signal.throwIfAborted();
*
* await asyncFunction2();
* signal.throwIfAborted();
*
* return result;
* }, { retriesMax: 10 });
*
* // Cancel the operation at any time
* setTimeout(() => abort(), 5000);
*
* const [err, result] = await promise;
* if (err?.name === 'AbortError') {
* console.log('Operation was cancelled');
* }
* ```
*
* @param handler - Async function that receives an AbortSignal.
* Should call `signal.throwIfAborted()` periodically to check for cancellation.
* @param options - Retry configuration
* @returns Tuple of [abort function, result promise]. The promise resolves to [error, result].
*/
export const abortableRetry = (handler, options) => {
const abortController = new AbortController();
const promise = to(retryAttempt(async () => {
abortController.signal.throwIfAborted();
const result = await handler(abortController.signal);
abortController.signal.throwIfAborted();
return result;
}, [], {
retriesMax: options.retriesMax
}).fail(async options => {
if (abortController.signal.aborted) {
throw new DOMException('Operation aborted', 'AbortError');
}
await options.timeFn();
return true;
}).exec());
return [() => abortController.abort(), promise];
};