Files
bitvid/js/utils/asyncUtils.js
T
google-labs-jules[bot]andPR0M3TH3AN ab441ce0c4 ⚡ Optimize watch history publishing with parallel execution
- Implemented `pMap` utility for concurrent async mapping with a limit.
- Refactored `publishRecords` in `js/nostr/watchHistory.js` to use `pMap` instead of serial `for...of` loop.
- Added `tests/benchmark_watch_history_publish.mjs` to verify performance.

Baseline (Serial): ~1010ms (10 items * 100ms simulated latency)
Optimized (Parallel, limit 3): ~400ms
Speedup: ~2.5x faster.

Co-authored-by: PR0M3TH3AN <[email protected]>
2026-02-05 19:38:13 +00:00

54 lines
1.4 KiB
JavaScript

/**
* Maps over an iterable with a concurrency limit.
*
* @param {Iterable} iterable - The items to map over.
* @param {Function} mapper - The async mapping function.
* @param {Object} options - Options object.
* @param {number} options.concurrency - The concurrency limit (default: Infinity).
* @returns {Promise<Array>} - The results of the mapping function in original order.
*/
export async function pMap(iterable, mapper, { concurrency = Infinity } = {}) {
const results = [];
const iterator = iterable[Symbol.iterator]();
let index = 0;
let active = 0;
let done = false;
let rejected = false;
return new Promise((resolve, reject) => {
function next() {
if (rejected) return;
if (done && active === 0) {
resolve(results);
return;
}
while (active < concurrency && !done) {
const nextItem = iterator.next();
if (nextItem.done) {
done = true;
if (active === 0) resolve(results);
return;
}
const currentIndex = index++;
active++;
Promise.resolve(nextItem.value)
.then((value) => mapper(value, currentIndex))
.then((result) => {
results[currentIndex] = result;
active--;
next();
})
.catch((err) => {
rejected = true;
reject(err);
});
}
}
next();
});
}