p-iterate
Version:
Iterate over promises as they're fulfilled.
70 lines • 2.31 kB
JavaScript
export async function* pIter(promises) {
// Typescript incorrectly narrows `state` on the assumption that it doesn't
// leak, so we manually widen it to its full type range.
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
let state = { label: 'accumulating', values: [] };
let count = 0;
for (const promise of promises) {
count++;
/* eslint-disable @typescript-eslint/no-loop-func */
Promise.resolve(promise)
.then((value) => {
if (state.label === 'yielded') {
state.resolve(value);
state = { label: 'accumulating', values: [] };
}
else if (state.label === 'accumulating') {
state.values.push(value);
}
})
.catch((error) => {
if (state.label === 'yielded') {
state.reject(error);
}
else if (state.label === 'accumulating') {
state = { label: 'rejected', reason: error };
}
});
/* eslint-enable @typescript-eslint/no-loop-func */
}
while (count > 0) {
count--;
if (state.label === 'rejected') {
throw state.reason;
}
else if (state.label === 'accumulating') {
if (state.values.length > 0) {
yield state.values.pop();
}
else {
// eslint-disable-next-line @typescript-eslint/no-loop-func
yield new Promise((resolve, reject) => {
state = { label: 'yielded', resolve, reject };
});
}
}
}
}
function* map(iterable, fn) {
let index = 0;
for (const item of iterable) {
yield fn(item, index++);
}
}
export function pIterSettled(promises) {
return pIter(map(promises, async (promise, index) => {
try {
return { status: 'fulfilled', value: await promise, index };
}
catch (error) {
return { status: 'rejected', reason: error, index };
}
}));
}
export function pIterEnumerated(promises) {
return pIter(map(promises, async (promise, index) => [
index,
await Promise.resolve(promise),
]));
}
//# sourceMappingURL=index.js.map