Add AbortSignal polyfills

This commit is contained in:
Alex Gleason 2025-06-15 12:35:47 -05:00
parent cd5376ff49
commit 1e179b4396
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
2 changed files with 84 additions and 3 deletions

78
src/lib/polyfills.ts Normal file
View File

@ -0,0 +1,78 @@
/**
* Polyfill for AbortSignal.any()
*
* AbortSignal.any() creates an AbortSignal that will be aborted when any of the
* provided signals are aborted. This is useful for combining multiple abort signals.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/any_static
*/
// Check if AbortSignal.any is already available
if (!AbortSignal.any) {
AbortSignal.any = function(signals: AbortSignal[]): AbortSignal {
// If no signals provided, return a signal that never aborts
if (signals.length === 0) {
return new AbortController().signal;
}
// If only one signal, return it directly for efficiency
if (signals.length === 1) {
return signals[0];
}
// Check if any signal is already aborted
for (const signal of signals) {
if (signal.aborted) {
// Create an already-aborted signal with the same reason
const controller = new AbortController();
controller.abort(signal.reason);
return controller.signal;
}
}
// Create a new controller for the combined signal
const controller = new AbortController();
// Function to abort the combined signal
const onAbort = (event: Event) => {
const target = event.target as AbortSignal;
controller.abort(target.reason);
};
// Listen for abort events on all input signals
for (const signal of signals) {
signal.addEventListener('abort', onAbort, { once: true });
}
// Clean up listeners when the combined signal is aborted
controller.signal.addEventListener('abort', () => {
for (const signal of signals) {
signal.removeEventListener('abort', onAbort);
}
}, { once: true });
return controller.signal;
};
}
/**
* Polyfill for AbortSignal.timeout()
*
* AbortSignal.timeout() creates an AbortSignal that will be aborted after a
* specified number of milliseconds.
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static
*/
// Check if AbortSignal.timeout is already available
if (!AbortSignal.timeout) {
AbortSignal.timeout = function(milliseconds: number): AbortSignal {
const controller = new AbortController();
setTimeout(() => {
controller.abort(new DOMException('The operation was aborted due to timeout', 'TimeoutError'));
}, milliseconds);
return controller.signal;
};
}

View File

@ -1,7 +1,10 @@
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client';
import App from './App.tsx' // Import polyfills first
import './index.css' import './lib/polyfills.ts';
import App from './App.tsx';
import './index.css';
// FIXME: a custom font should be used. Eg: // FIXME: a custom font should be used. Eg:
// import '@fontsource-variable/<font-name>'; // import '@fontsource-variable/<font-name>';