Skip to content

Commit 977a562

Browse files
authored
resolving issues with fails vs successes
1 parent bc337c4 commit 977a562

1 file changed

Lines changed: 88 additions & 61 deletions

File tree

ResourceLoader.js

Lines changed: 88 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ const ResourceLoader = (() => {
2525
}
2626
}
2727

28-
// Function to categorize errors for better logging
2928
function categorizeError(error, fileType, url) {
3029
if (error.name === "AbortError") {
3130
return { type: "abort", message: `Fetch aborted for: ${url}` };
@@ -61,9 +60,7 @@ const ResourceLoader = (() => {
6160
}
6261
}
6362

64-
// Validate crossorigin and integrity attributes for security-sensitive resources
6563
function validateSecurityAttributes(element, fileType, attributes) {
66-
// Cross-origin validation
6764
if (fileType === "js" || fileType === "css") {
6865
if (
6966
attributes.crossorigin &&
@@ -77,7 +74,6 @@ const ResourceLoader = (() => {
7774
}
7875
}
7976

80-
// Integrity validation for JS and CSS files
8177
if (fileType === "js" || fileType === "css") {
8278
if (!attributes.integrity) {
8379
log(
@@ -102,11 +98,10 @@ const ResourceLoader = (() => {
10298
}
10399
});
104100

105-
// Apply security-related attributes after general attributes
106101
validateSecurityAttributes(element, fileType, attributes);
107102
}
108103

109-
async function include(urls, options = {}) {
104+
function include(urls, options = {}) {
110105
if (!Array.isArray(urls)) {
111106
urls = [urls];
112107
}
@@ -122,17 +117,18 @@ const ResourceLoader = (() => {
122117
crossorigin = false,
123118
logLevel = "warn",
124119
onError = null,
120+
onSuccess = null,
125121
retries = 0,
126122
retryDelay = 1000,
127123
deferScriptsUntilReady = true,
128124
batchSize = 5,
129125
maxConcurrency = 3,
130-
priority = 0, // New option for resource priority
126+
priority = 0,
127+
removeFailedElements = true,
131128
} = options;
132129

133130
setLoggingLevel(logLevel);
134131

135-
// Sort resources by priority (higher priority resources load first)
136132
const sortedUrls = urls.sort((a, b) => {
137133
const priorityA = a.priority || 0;
138134
const priorityB = b.priority || 0;
@@ -200,7 +196,11 @@ const ResourceLoader = (() => {
200196
}
201197
if (retryCount < retries) {
202198
log(`Retrying to load resource: ${finalUrl}`, "warn");
203-
setTimeout(() => loadResource(url, retryCount + 1), retryDelay);
199+
setTimeout(() => {
200+
loadResource(url, retryCount + 1)
201+
.then(resolve)
202+
.catch(reject);
203+
}, retryDelay);
204204
}
205205
};
206206

@@ -237,13 +237,14 @@ const ResourceLoader = (() => {
237237
finalUrl
238238
);
239239
reject(categorizedError);
240-
if (onError) onError(categorizedError);
240+
if (onError) onError(categorizedError, url);
241241
if (retryCount < retries) {
242242
log(`Retrying to load resource: ${finalUrl}`, "warn");
243-
setTimeout(
244-
() => loadResource(url, retryCount + 1),
245-
retryDelay
246-
);
243+
setTimeout(() => {
244+
loadResource(url, retryCount + 1)
245+
.then(resolve)
246+
.catch(reject);
247+
}, retryDelay);
247248
}
248249
});
249250
cancel = () => controller.abort();
@@ -284,13 +285,14 @@ const ResourceLoader = (() => {
284285
finalUrl
285286
);
286287
reject(categorizedError);
287-
if (onError) onError(categorizedError);
288+
if (onError) onError(categorizedError, url);
288289
if (retryCount < retries) {
289290
log(`Retrying to load resource: ${finalUrl}`, "warn");
290-
setTimeout(
291-
() => loadResource(url, retryCount + 1),
292-
retryDelay
293-
);
291+
setTimeout(() => {
292+
loadResource(url, retryCount + 1)
293+
.then(resolve)
294+
.catch(reject);
295+
}, retryDelay);
294296
}
295297
});
296298
return;
@@ -312,23 +314,26 @@ const ResourceLoader = (() => {
312314
finalUrl
313315
);
314316
reject(categorizedError);
315-
if (onError) onError(categorizedError);
317+
if (onError) onError(categorizedError, url);
316318
if (retryCount < retries) {
317319
log(`Retrying to load resource: ${finalUrl}`, "warn");
318-
setTimeout(
319-
() => loadResource(url, retryCount + 1),
320-
retryDelay
321-
);
320+
setTimeout(() => {
321+
loadResource(url, retryCount + 1)
322+
.then(resolve)
323+
.catch(reject);
324+
}, retryDelay);
322325
}
323326
});
324327
cancel = () => controller.abort();
325328
return;
326329
default:
327-
reject(new Error(`Unsupported file type: ${fileType}`));
330+
const error = new Error(`Unsupported file type: ${fileType}`);
331+
reject(error);
328332
log(
329333
`Failed to load unsupported file type: ${finalUrl}`,
330334
"error"
331335
);
336+
return;
332337
}
333338

334339
applyAttributes(element, attributes, fileType);
@@ -338,38 +343,46 @@ const ResourceLoader = (() => {
338343
element.onload = () => {
339344
if (!timedOut) {
340345
clearTimeout(timeoutId);
341-
342-
// Check if resource was really loaded (some resources may trigger onload without being valid)
343-
if (
344-
element.naturalWidth === 0 ||
345-
element.readyState === "complete"
346-
) {
347-
log(`Resource loaded from: ${finalUrl}`, "verbose");
348-
resourceStates[url] = "loaded";
349-
resolve();
350-
} else {
351-
log(`Failed to load resource from: ${finalUrl}`, "error");
352-
reject(new Error(`Failed to load resource: ${finalUrl}`));
353-
}
346+
log(`Resource loaded from: ${finalUrl}`, "verbose");
347+
resourceStates[url] = "loaded";
348+
resolve();
349+
if (onSuccess) onSuccess(url);
354350
}
355351
};
356352

357353
element.onerror = () => {
358354
clearTimeout(timeoutId);
355+
359356
const loadError = new Error(
360357
`Failed to load resource from: ${finalUrl}`
361358
);
359+
362360
const categorizedError = categorizeError(
363361
loadError,
364362
fileType,
365363
finalUrl
366364
);
365+
367366
reject(categorizedError);
367+
368368
log(`Failed to load resource from: ${finalUrl}`, "warn");
369+
369370
resourceStates[url] = "unloaded";
371+
372+
if (removeFailedElements && element && element.parentNode) {
373+
element.parentNode.removeChild(element);
374+
log(`Removed failed element: ${finalUrl}`, "verbose");
375+
}
376+
377+
if (onError) onError(categorizedError, url);
378+
370379
if (retryCount < retries) {
371380
log(`Retrying to load resource: ${finalUrl}`, "warn");
372-
setTimeout(() => loadResource(url, retryCount + 1), retryDelay);
381+
setTimeout(() => {
382+
loadResource(url, retryCount + 1)
383+
.then(resolve)
384+
.catch(reject);
385+
}, retryDelay);
373386
}
374387
};
375388

@@ -409,37 +422,51 @@ const ResourceLoader = (() => {
409422
} else {
410423
loadScriptWhenReady();
411424
}
412-
}).catch((err) => {
413-
log(`Error loading resource: ${url}`, "warn");
414-
return Promise.resolve();
415425
}),
416426
cancel,
417427
}).promise;
418428
};
419429

420-
const loadWithConcurrencyLimit = async (
421-
resources,
422-
loadFn,
423-
maxConcurrency
424-
) => {
425-
let active = 0;
430+
function loadWithConcurrencyLimit(resources, loadFn, maxConcurrency) {
426431
let index = 0;
432+
const results = [];
433+
const total = resources.length;
434+
435+
return new Promise((resolve) => {
436+
const startNext = () => {
437+
if (index >= total) {
438+
if (results.length === total) {
439+
resolve(results);
440+
}
441+
return;
442+
}
427443

428-
const processNext = async () => {
429-
while (active < maxConcurrency && index < resources.length) {
430-
const currentUrl = resources[index++];
431-
active++;
432-
loadFn(currentUrl).finally(() => {
433-
active--;
434-
processNext();
435-
});
436-
}
437-
};
444+
const currentIndex = index++;
445+
const url = resources[currentIndex];
446+
447+
loadFn(url)
448+
.then(() => {
449+
results[currentIndex] = { status: "fulfilled", value: url };
450+
startNext();
451+
})
452+
.catch((error) => {
453+
results[currentIndex] = {
454+
status: "rejected",
455+
reason: error,
456+
url,
457+
};
458+
startNext();
459+
});
460+
};
438461

439-
await processNext();
440-
};
462+
// Start initial batch
463+
for (let i = 0; i < Math.min(maxConcurrency, total); i++) {
464+
startNext();
465+
}
466+
});
467+
}
441468

442-
await loadWithConcurrencyLimit(urls, loadResource, maxConcurrency);
469+
return loadWithConcurrencyLimit(sortedUrls, loadResource, maxConcurrency);
443470
}
444471

445472
function unloadResource(url) {

0 commit comments

Comments
 (0)