The following Typescript performs each call to doSomething(action)
one at a time. (Meaning the second item in the list does not get a call made until the first one is done).
async performActionsOneAtATime() {
for (let action of listOfActions) {
const actionResult = await doSomethingOnServer(action);
console.log(`Action Done: ${actionResult}`);
}
}
This one will send all the requests to the server right away (without waiting for any responses):
async performActionsInParallel() {
for (let action of listOfActions) {
const actionResultPromise = doSomething(action);
actionResultPromise.then((actionResult) => {
console.log(`Action Done: ${actionResult}`);
});
}
}
But what I really need is a way to throttle them. Maybe have 10 or 20 calls open at a time. (One at at a time is too slow, but all 600 will overload the server.)
But I am having a hard time figuring this out.
Any suggestions on how I can throttle the number of calls to X open at a time?
(This question uses TypeScript, but I would be fine with an ES6 JavaScript answer.)
You can do this with a pub-sub pattern. I too am not familiar with typescipt, and I don't know if this is happening in the browser or at the backend. I'll just write the pseudoCode for this (assuming it's backend):
EventEmitter is part of NodeJS, if you are working in Node. If in the browser, you can use the normal events model. The key idea here is the Publish-Subscribe pattern.
You can do this in one short function. (Update: Returns values in order per naomik's suggestion.)
EDIT
Jeff Bowman has vastly improved his answer to resolve meaningful values. Feel free to view the history of this answer to understand why the resolved values are so important/useful.
throttlep
This solution closely mimics the native
Promise.all
How it's the same …
How it's different …
Console output
Inputs are run in order; Resolved results are in the same order as the inputs
Practical use
Let's look at a more practical code example. This code is tasked with fetching a set of images from a server. This is how we might use
throttlep
to throttle the amount of simultaneous requests to 3 at a timeThere isn't anything built-in for this, so you'll have to build your own. AFAIK, there's no library for this yet, either.
First, start with a "deferral" - a promise that allows external code to resolve it:
Then you can define a "wait queue", which represents all the code blocks that are waiting to enter the critical section:
Finally you can define an async semaphore, as such:
Example usage:
This method first creates a throttler and then immediately starts all the asynchronous operations. Each asynchronous operation will first (asynchronously) wait for the semaphore to be free, then perform the action, and finally release the semaphore (allowing another one in). When all asynchronous operations have completed, all the results are retrieved.
Warning: this code is 100% completely untested. I haven't even tried it once.