Releasing thread and URL reference when the workerized function is not needed
Great library, very useful stuff and absolutely love the size. :)
I've only recently started learning about Web Workers and took a look at the source code. So apologies in advance if I am wrong ;). 2 things caught my eyes:
const workerURL = URL.createObjectURL(new Blob([script]));
// Create an "inline" worker (1:1 at definition time)
const worker = new Worker(workerURL);
So if we do something like the following snippet (taken from the README), it seems that each new function instantiated via greenlet(...) will reserve a new thread and a new URL reference.
import greenlet from 'greenlet'
let getName = greenlet( async username => {
let url = `https://api.github.com/users/${username}`
let res = await fetch(url)
let profile = await res.json()
return profile.name
})
console.log(await getName('developit'))
So, if there is a case wherein I don't need to use getName after a certain point in my code, those resources are still trapped. They may be very less in size to be of a practical concern, but I am not sure about it and would love if anyone can comment on that.
However, if the output function getName comes with a dispose method which releases those references, it could be useful. WDYT? Something like:
getName.dispose() // Release references
Internally, it could call:
window.URL.revokeObjectURL(workerURL);
worker.terminate();
Post dispose, getName can itself become undefined so it's not callable. Or can throw a more informative error: The function is disposed/discarded due to .dispose() call..
Is there a downside to this approach if the contributors already considered any similar approach?
function greenlet(fn) {
const script = `self.onmessage = e => self.postMessage((${fn})(e.data));`;
const workerURL = URL.createObjectURL(new Blob([script]));
const worker = new Worker(workerURL);
const instance = (...args) =>
new Promise((resolve, reject) => {
const messageHandler = (e) => {
worker.removeEventListener('message', messageHandler);
resolve(e.data);
};
worker.addEventListener('message', messageHandler);
worker.postMessage(args);
});
instance.dispose = () => {
URL.revokeObjectURL(workerURL);
worker.terminate();
};
return instance;
}