feat: extract FontLoadQueue with retry tracking
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import type { FontLoadRequestConfig } from '../../../types';
|
||||
import { FontLoadQueue } from './FontLoadQueue';
|
||||
|
||||
const config = (id: string): FontLoadRequestConfig => ({
|
||||
id,
|
||||
name: id,
|
||||
url: `https://example.com/${id}.woff2`,
|
||||
weight: 400,
|
||||
});
|
||||
|
||||
describe('FontLoadQueue', () => {
|
||||
let queue: FontLoadQueue;
|
||||
|
||||
beforeEach(() => {
|
||||
queue = new FontLoadQueue();
|
||||
});
|
||||
|
||||
it('enqueue returns true for a new key', () => {
|
||||
expect(queue.enqueue('a@400', config('a'))).toBe(true);
|
||||
});
|
||||
|
||||
it('enqueue returns false for an already-queued key', () => {
|
||||
queue.enqueue('a@400', config('a'));
|
||||
expect(queue.enqueue('a@400', config('a'))).toBe(false);
|
||||
});
|
||||
|
||||
it('has returns true after enqueue, false after flush', () => {
|
||||
queue.enqueue('a@400', config('a'));
|
||||
expect(queue.has('a@400')).toBe(true);
|
||||
queue.flush();
|
||||
expect(queue.has('a@400')).toBe(false);
|
||||
});
|
||||
|
||||
it('flush returns all entries and atomically clears the queue', () => {
|
||||
queue.enqueue('a@400', config('a'));
|
||||
queue.enqueue('b@700', config('b'));
|
||||
const entries = queue.flush();
|
||||
expect(entries).toHaveLength(2);
|
||||
expect(queue.has('a@400')).toBe(false);
|
||||
expect(queue.has('b@700')).toBe(false);
|
||||
});
|
||||
|
||||
it('isMaxRetriesReached returns false below MAX_RETRIES', () => {
|
||||
queue.incrementRetry('a@400');
|
||||
queue.incrementRetry('a@400');
|
||||
expect(queue.isMaxRetriesReached('a@400')).toBe(false);
|
||||
});
|
||||
|
||||
it('isMaxRetriesReached returns true at MAX_RETRIES (3)', () => {
|
||||
queue.incrementRetry('a@400');
|
||||
queue.incrementRetry('a@400');
|
||||
queue.incrementRetry('a@400');
|
||||
expect(queue.isMaxRetriesReached('a@400')).toBe(true);
|
||||
});
|
||||
|
||||
it('clear resets queue and retry counts', () => {
|
||||
queue.enqueue('a@400', config('a'));
|
||||
queue.incrementRetry('a@400');
|
||||
queue.incrementRetry('a@400');
|
||||
queue.incrementRetry('a@400');
|
||||
queue.clear();
|
||||
expect(queue.has('a@400')).toBe(false);
|
||||
expect(queue.isMaxRetriesReached('a@400')).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { FontLoadRequestConfig } from '../../../types';
|
||||
|
||||
/**
|
||||
* Manages the font load queue and per-font retry counts.
|
||||
*
|
||||
* Scheduling (when to drain the queue) is handled by the orchestrator —
|
||||
* this class is purely concerned with what is queued and whether retries are exhausted.
|
||||
*/
|
||||
export class FontLoadQueue {
|
||||
#queue = new Map<string, FontLoadRequestConfig>();
|
||||
#retryCounts = new Map<string, number>();
|
||||
|
||||
readonly #MAX_RETRIES = 3;
|
||||
|
||||
/**
|
||||
* Adds a font to the queue.
|
||||
* @returns `true` if the key was newly enqueued, `false` if it was already present.
|
||||
*/
|
||||
enqueue(key: string, config: FontLoadRequestConfig): boolean {
|
||||
if (this.#queue.has(key)) return false;
|
||||
this.#queue.set(key, config);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically snapshots and clears the queue.
|
||||
* @returns All queued entries at the time of the call.
|
||||
*/
|
||||
flush(): Array<[string, FontLoadRequestConfig]> {
|
||||
const entries = Array.from(this.#queue.entries());
|
||||
this.#queue.clear();
|
||||
return entries;
|
||||
}
|
||||
|
||||
/** Returns `true` if the key is currently in the queue. */
|
||||
has(key: string): boolean {
|
||||
return this.#queue.has(key);
|
||||
}
|
||||
|
||||
/** Increments the retry count for a font key. */
|
||||
incrementRetry(key: string): void {
|
||||
this.#retryCounts.set(key, (this.#retryCounts.get(key) ?? 0) + 1);
|
||||
}
|
||||
|
||||
/** Returns `true` if the font has reached or exceeded the maximum retry limit. */
|
||||
isMaxRetriesReached(key: string): boolean {
|
||||
return (this.#retryCounts.get(key) ?? 0) >= this.#MAX_RETRIES;
|
||||
}
|
||||
|
||||
/** Clears all queued fonts and resets all retry counts. */
|
||||
clear(): void {
|
||||
this.#queue.clear();
|
||||
this.#retryCounts.clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user