JSFiddle - React, Tailwind, and code Playground
JavaScript
async function* makeALotOfWork() {
let value = 0;
while (true) {
yield ({ delay: Math.floor(Math.random() * 1000) + 10, value: value++ });
}
}
async function* map(fn, n) {
try {
// Start n work
const parallel = new Set();
for (let i = 0; i < n; ++i) {
const itr = await this.next();
if (itr.done) return;
parallel.add({ value: itr.value, promise: fn(itr.value) });
}
// Process the work yielding the first one done in the set of n work
while (parallel.length != 0) {
const task = await Promise.race([...parallel].map(async currentTask => {
await currentTask.promise;
return currentTask;
}));
parallel.delete(task);
yield task.value;
// Add 1 more work
const itr = await this.next();
if (itr.done) return;
parallel.add({ value: itr.value, promise: fn(itr.value) });
}
} finally {
console.log('map done');
this?.return();
}
}
[].values().__proto__.__proto__.map = map;
(async function*(){})().__proto__.__proto__.__proto__.map = map;
async function work(t) {
t.value *= 2;
await new Promise(resolve => setTimeout(resolve, t.delay));
return t;
}
(async () => {
let workDone = 0;
let totalDelay = 0;
const currentTime = performance.now();
for await (const t of makeALotOfWork().map(work, 5).map(work, 5)) {
console.log(t.value, t.delay);
totalDelay += t.delay;
workDone++;
if (workDone > 20) {
break;
}
}
console.log(`Work Total Time: ${totalDelay} Elapsed Time: ${performance.now() - currentTime}`);
})();