i really like context managers from python. i recently re-discovered that generator functions combined with try/catch and for-of loops can simulate it easily. i decided to use the prefix using on the related function in order to make it more clear that this is not really a thing to be iterated as much as used.
this definitely feels like an abuse of the iterator protocol, but at the same time, it feels so clean?? automatic cleanup, baby!
function* usingAbortSignal() {
const abortController = new AbortController();
try {
yield abortController.signal;
} finally {
abortController.abort();
}
}
export async function loadUrlAsElement(url) {
for (const signal of usingAbortSignal()) {
return await new Promise((resolve, reject) => {
const image = new Image();
function onLoad() {
resolve(image);
}
function onError() {
reject(new Error(`Failed to load image: ${url}`));
}
image.addEventListener("load", onLoad, { signal });
image.addEventListener("error", onError, { signal });
image.src = url;
});
}
}

