How do I do something like $q.all
but limiting how many promises are executed concurrently?
My question is just like How can I limit Q promise concurrency?
I want no more than 5 process spawned at a time
The accepted answer for that other question is a library written for promise wrapped to work with Q.
But I'm interested specifically in a solution for Angular's $q
rather than for Q
.
Background: The problem being solved:
I have a bunch of files to download in 2 steps: a) Get URL b) download file.
The browser limits how many files can be retrieved concurrently, so when the straightforward use of promises with $q.all
fires off all the downloads, only N happen right away, e.g. 6 in Chrome, while the rest are delayed. (see Max parallel http connections in a browser?)
Problem is that the URLs have expiry, so by the time the browser executes the N+1thfile download, the URL is no longer valid.
So I want to do something like throttled.all(6, promises)
rather than $q.all(promise)
If the resolving of 'all' Promises is irrelevant (like you are updating some Elements on the page and you don't care if it's progressive and not in one 'whoosh') I have created a simple TaskQueue Service. It will not wait for all Promises to be resolved but rather it will process all added Promises/Functions/Tasks it gets and with a max. concurrency of a configured limit value.
As I only found this and some other StackOverflows not helping with my problem I had. So I now give something back to the community I guess. Hope it helps somebody.
It uses modern JS stuff like const and lambda expressions, but you may simply let it compile down from a precompiler like babel if you just want the 'old' stuff.
https://gist.github.com/Blackskyliner/8b1bafed326044fa4f8b1ba2627d1117
It just simply processes its queue after Tasks, which are just anonymous functions, returning a promise or value, are added. It will adhere to a configurable 'maxConcurrentTasks' variable on the service.
If the Task returns a promise which returns a promise and so on it will always use the initial 'slot' within the queue. So it will free the 'slot' for an other added Task after the whole Task Promise chain is resolved (or rejected).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With