I want to implement a function to dynamically load js scripts, if the loading fails, retry it, the retry limit is three times, and return the loading result.
async function getScript(url: string, retryTime = 0, promise?: any) {
const element = window.document.createElement('script');
element.src = url;
element.type = 'text/javascript';
element.async = true;
const p = promise || {
resolve: (v: boolean) => { },
reject: (msg: string) => { },
};
element.onload = () => {
p.resolve(true);
};
element.onerror = () => {
const msg = `Dynamic Script Error: ${url}`;
if (retryTime < 3) {
console.log('retry load');
document.head.removeChild(element);
return getScript(url, retryTime + 1, p);
}
p.reject(msg);
};
document.head.appendChild(element);
return new Promise((rl, rj) => {
p.resolve = rl;
p.reject = rj;
});
}
But when I call this function, if load error in first time, and success in second time. document.head.appendChild(element)will throw an error, So, i can't catch the error in outside.
What can I do.
Seems overly complicated. Here's a cleaner, more decoupled solution:
async function getScript(url) {
return new Promise((resolve, reject) => {
const element = document.createElement('script');
element.src = url;
element.type = 'text/javascript';
element.async = true;
element.onload = () => resolve();
element.onerror = () => reject();
document.head.appendChild(element);
});
}
async function retrying(func, attempts) {
for (let attempt = 1; attempt <= attempts; attempt++) {
try {
return await func();
} catch (ex) {
console.warn(`Failed in attempt ${attempt}`);
}
}
throw new Error(`Failed after ${attempts} attempts`);
}
Usage:
retrying(() => getScript(url), 3);