Skip to content

Instantly share code, notes, and snippets.

@RubaXa
Last active December 24, 2019 07:38
Show Gist options
  • Save RubaXa/baf645d76785b2962f0c93297cb72a82 to your computer and use it in GitHub Desktop.
Save RubaXa/baf645d76785b2962f0c93297cb72a82 to your computer and use it in GitHub Desktop.
Worker Pool
function createWorkerPool<
A extends object,
E extends object,
R extends any,
>(size: number, init: () => E, worker: (args: A, env: E) => Promise<R>) {
const pool = [] as Array<{
args: A;
resolve: (promise: Promise<R>) => void
}>;
const units = [] as Array<{
env: E,
idle: boolean;
}>;
function tick() {
if (pool.length) {
let unit = units.find(u => u.idle);
if (units.length < size && !unit) {
unit = {
env: init(),
idle: true,
};
units.push(unit);
}
if (unit) {
const task = pool.shift();
if (!task) {
return;
}
unit.idle = false;
const promise = Promise.resolve(worker(task.args, unit.env));
task.resolve(promise);
promise.then(finish(unit), finish(unit))
}
}
}
function finish(unit) {
return () => {
unit.idle = true;
tick();
};
}
return (args: A) => new Promise<R>((resolve) => {
pool.push({
args,
resolve,
});
tick();
});
}
@RubaXa
Copy link
Author

RubaXa commented Mar 26, 2018

For example

const preloadImage = createWorkerPool(
	5, // workers
	() => {
		const image = new Image;
		let retry = 0;
		image.onerror = () => {
			setTimeout(() => {
				retry++;
				image.src = image.src.replace(/[?&]try\d+/, '') + (image.src.includes('?') ? '&try' : '?try') + retry;
			}, 500);
		};
		// env
		return {image};
	},
	({src}, {image}) => new Promise(resolve => {
		image.src = src;
		image.onload = resolve;
		image.naturalWidth && resolve();
	}).then(() => image.src)
);

// Preload all images in 5 flows
[].forEach.call(document.querySelectorAll('img[data-src]'), (el) => {
	preloadImage({src: el.dataset.src}).then(src => {
		el.src = src;
	});
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment