49 lines
1.1 KiB
JavaScript
49 lines
1.1 KiB
JavaScript
|
import pLimit from 'p-limit';
|
||
|
|
||
|
class EndError extends Error {
|
||
|
constructor(value) {
|
||
|
super();
|
||
|
this.value = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The input can also be a promise, so we await it.
|
||
|
const testElement = async (element, tester) => tester(await element);
|
||
|
|
||
|
// The input can also be a promise, so we `Promise.all()` them both.
|
||
|
const finder = async element => {
|
||
|
const values = await Promise.all(element);
|
||
|
if (values[1] === true) {
|
||
|
throw new EndError(values[0]);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
export default async function pLocate(
|
||
|
iterable,
|
||
|
tester,
|
||
|
{
|
||
|
concurrency = Number.POSITIVE_INFINITY,
|
||
|
preserveOrder = true,
|
||
|
} = {},
|
||
|
) {
|
||
|
const limit = pLimit(concurrency);
|
||
|
|
||
|
// Start all the promises concurrently with optional limit.
|
||
|
const items = [...iterable].map(element => [element, limit(testElement, element, tester)]);
|
||
|
|
||
|
// Check the promises either serially or concurrently.
|
||
|
const checkLimit = pLimit(preserveOrder ? 1 : Number.POSITIVE_INFINITY);
|
||
|
|
||
|
try {
|
||
|
await Promise.all(items.map(element => checkLimit(finder, element)));
|
||
|
} catch (error) {
|
||
|
if (error instanceof EndError) {
|
||
|
return error.value;
|
||
|
}
|
||
|
|
||
|
throw error;
|
||
|
}
|
||
|
}
|