refactor: extract #fetchChunk, replace Promise.allSettled with self-describing results
This commit is contained in:
@@ -191,34 +191,7 @@ export class AppliedFontsManager {
|
||||
// ==================== PHASE 1: Concurrent Fetching ====================
|
||||
// Fetch multiple font files in parallel since network I/O is non-blocking
|
||||
for (let i = 0; i < entries.length; i += concurrency) {
|
||||
// Process in chunks based on concurrency limit
|
||||
const chunk = entries.slice(i, i + concurrency);
|
||||
const results = await Promise.allSettled(
|
||||
chunk.map(async ([key, config]) => {
|
||||
this.statuses.set(key, 'loading');
|
||||
// Fetch buffer via cache (checks memory → Cache API → network)
|
||||
const buffer = await this.#cache.get(config.url, this.#abortController.signal);
|
||||
buffers.set(key, buffer);
|
||||
}),
|
||||
);
|
||||
|
||||
// Handle fetch errors - set status and increment retry count
|
||||
for (let j = 0; j < results.length; j++) {
|
||||
if (results[j].status === 'rejected') {
|
||||
const [key, config] = chunk[j];
|
||||
const reason = (results[j] as PromiseRejectedResult).reason;
|
||||
// Aborted fetches are not retriable failures — skip silently
|
||||
const isAbort = reason instanceof FontFetchError
|
||||
&& reason.cause instanceof Error
|
||||
&& reason.cause.name === 'AbortError';
|
||||
if (isAbort) continue;
|
||||
if (reason instanceof FontFetchError) {
|
||||
console.error(`Font fetch failed: ${config.name}`, reason);
|
||||
}
|
||||
this.statuses.set(key, 'error');
|
||||
this.#queue.incrementRetry(key);
|
||||
}
|
||||
}
|
||||
await this.#fetchChunk(entries.slice(i, i + concurrency), buffers);
|
||||
}
|
||||
|
||||
// ==================== PHASE 2: Sequential Parsing ====================
|
||||
@@ -250,6 +223,43 @@ export class AppliedFontsManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a chunk of fonts concurrently and populates `buffers` with successful results.
|
||||
* Each promise carries its own key and config so results need no index correlation.
|
||||
* Aborted fetches are silently skipped; other errors set status to `'error'` and increment retry.
|
||||
*/
|
||||
async #fetchChunk(
|
||||
chunk: Array<[string, FontLoadRequestConfig]>,
|
||||
buffers: Map<string, ArrayBuffer>,
|
||||
): Promise<void> {
|
||||
const results = await Promise.all(
|
||||
chunk.map(async ([key, config]) => {
|
||||
this.statuses.set(key, 'loading');
|
||||
try {
|
||||
const buffer = await this.#cache.get(config.url, this.#abortController.signal);
|
||||
buffers.set(key, buffer);
|
||||
return { ok: true as const, key };
|
||||
} catch (reason) {
|
||||
return { ok: false as const, key, config, reason };
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
for (const result of results) {
|
||||
if (result.ok) continue;
|
||||
const { key, config, reason } = result;
|
||||
const isAbort = reason instanceof FontFetchError
|
||||
&& reason.cause instanceof Error
|
||||
&& reason.cause.name === 'AbortError';
|
||||
if (isAbort) continue;
|
||||
if (reason instanceof FontFetchError) {
|
||||
console.error(`Font fetch failed: ${config.name}`, reason);
|
||||
}
|
||||
this.statuses.set(key, 'error');
|
||||
this.#queue.incrementRetry(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a fetched buffer into a {@link FontFace}, registers it with `document.fonts`,
|
||||
* and updates reactive status. On failure, sets status to `'error'` and increments the retry count.
|
||||
|
||||
Reference in New Issue
Block a user