Skip to content

Instantly share code, notes, and snippets.

@fronterior
Created January 12, 2022 07:53
Show Gist options
  • Save fronterior/9e9a28a840334c374c46df74d958add6 to your computer and use it in GitHub Desktop.
Save fronterior/9e9a28a840334c374c46df74d958add6 to your computer and use it in GitHub Desktop.
class TPromise<T> extends Promise<T> {
static TimeoutError = class extends Error {};
constructor(
f: (
resolve: (value: T | PromiseLike<T>) => void,
reject: (reason?: any) => void
) => void,
timeout: number = Infinity
) {
let resolve, reject;
super((res, rej) => {
resolve = res;
reject = rej;
});
const timer =
timeout === Infinity
? null
: setTimeout(() => {
reject(
new TPromise.TimeoutError(`Load timeout for promise: ${timeout}`)
);
}, timeout);
f(
(val: T | PromiseLike<T>) => {
resolve(val);
clearTimeout(timer);
},
(err) => {
reject(err);
clearTimeout(timer);
}
);
}
}
class ImageLoader extends TPromise<HTMLImageElement> {
static CancelError = class extends Error {};
public img: HTMLImageElement;
constructor(
src: string,
{
timeout = Infinity,
crossOrigin,
}: Partial<{
timeout: number;
crossOrigin: string;
}> = {}
) {
const img = new Image();
const p = new TPromise<HTMLImageElement>((resolve, reject) => {
if (timeout !== Infinity)
setTimeout(() => {
reject(new Error(`Load timeout for [${src}]:${timeout}ms`));
}, timeout);
img.crossOrigin = crossOrigin;
img.onload = () => {
resolve(img);
};
img.onerror = (err) => {
if (img.getAttribute("src") === "")
reject(new ImageLoader.CancelError(`Cancel image loading.`));
else reject(err);
};
img.src = src;
}, timeout).catch((err) => {
if (err instanceof TPromise.TimeoutError) img.removeAttribute("src");
throw err;
});
super((res, rej) => p.then(res, rej));
this.img = img;
}
cancel() {
this.img.src = "";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment