190a0dba9b
- Cache follow list and author profiles in localStorage for instant feed on return visits - Prefetch profile images via <link rel=preload> for instant avatar rendering - Replace Radix Avatar with lightweight component that renders <img> immediately - Lazy-load route components (React.lazy) reducing main bundle from 1.7MB to 920KB - Dynamic import hls.js (1.3MB) only when visiting stream pages - Remove unused Buffer polyfill - Add pre-React loading spinner in index.html outside #root for seamless handoff - Fix 3-5s feed rerender caused by NostrSync relay/settings sync - Fix Zod 4 strict mode rejecting feedSettings with extra/missing keys from localStorage - Fix useLocalStorage skip update when value reference unchanged - Reduce eoseTimeout from default to 600ms
78 lines
2.3 KiB
TypeScript
78 lines
2.3 KiB
TypeScript
/**
|
|
* 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;
|
|
};
|
|
} |