Some nice way of async iterating?
See original GitHub issueI’m trying to limit uploads to 10 simultaneously, and I’m doing it like this:
const uploadSema = new Sema(10)
for (const upload of uploads) {
await uploadSema.acquire()
uploadOne(upload).finally(() => uploadSema.release())
}
await uploadSema.drain()
It’s reasonably nice, but I was wondering if there wasn’t a way to make this nicer.
I moved the logic to this helper function
export const queuedWork = async (items, fn, workers = 10) => {
const sema = new Sema(workers)
let threw = null
for (const item of items) {
if (threw) break
await sema.acquire()
// eslint-disable-next-line promise/catch-or-return
Promise.resolve(fn(item))
.catch(err => {
threw = err
})
.finally(() => sema.release())
}
await sema.drain()
if (threw) throw threw
}
Is this a good way of going about it? Is there maybe a more elegant way?
(wrote these tests too)
test('queuedWork async', async () => {
const out = []
await queuedWork([1, 5, 7, 89, 2], async n => out.push(n), 2)
expect(out).toEqual([1, 5, 7, 89, 2])
})
test('queuedWork sync', async () => {
const out = []
await queuedWork([1, 5, 7, 89, 2], n => out.push(n), 2)
expect(out).toEqual([1, 5, 7, 89, 2])
})
test('queuedWork throws', async () => {
const out = []
await expect(
queuedWork(
[1, 2, 3, 4, 5],
async n => {
if (n === 2) throw new Error('meep')
else out.push(n)
},
2
)
).rejects.toThrow('meep')
expect(out).toEqual([1, 3])
})
test('queuedWork throws sync', async () => {
const out = []
await expect(
queuedWork(
[1, 2, 3, 4, 5],
n => {
if (n === 2) throw new Error('meep')
else out.push(n)
},
2
)
).rejects.toThrow('meep')
expect(out).toEqual([1])
})
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (2 by maintainers)
Top Results From Across the Web
Async iteration and generators - The Modern JavaScript Tutorial
Asynchronous iteration allow us to iterate over data that comes asynchronously, on-demand. Like, for instance, when we download something ...
Read more >Iterating Asynchronously: How to use async & await ... - Medium
This method is used when you have a bunch of tasks that you want to await all at once. We then await the...
Read more >for await...of - JavaScript - MDN Web Docs
The for await...of statement creates a loop iterating over async iterable objects as well as sync iterables. This statement can only be used ......
Read more >How to use async/await inside loops in JavaScript
Iterating through items and dealing with asynchronous logic (i.e. API calls) are probably two of the most common tasks we have to perform...
Read more >what's the best method to handle async iterators and await?
If you want to run the operations sequentially, then use a regular for loop instead of .forEach() since for will wait for your...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@cardin but in both cases it does use O(n) memory, and at some point that becomes too much.
Processing an array with “workers” uses only O(nWorkers) memory.
V8 is pretty efficient, but if small changes (amount of code is similar) can use less memory, that’s a good thing, right? Less memory trashing => less GC => faster, even apart from host constraints
@wmertens oh right. I have seen that happening (OOM). I have used array-split for splitting a long array and processing it in chunks.
Maybe I could add it to the examples.