JavaScript Weighted Promises Pool

Sergei
Pipedrive R&D Blog
Published in
2 min readApr 23, 2019

Some time ago I was faced with an issue downloading files with Node.js.
Since file downloading in Node.js is an asynchronous operation, this issue looked interesting for me because with javascript promises you either can download files one-by-one with ‘Promise.then’, or start to download all of them asynchronously and wait for a result with ‘Promise.all’. As far as I know, in javascript there is no native mechanism to split asynchronous tasks by several queues when queues are executed asynchronously, but tasks inside a queue are executed sequentially.

Although this issue may be something that other developers have solved with different libraries, I wanted to tackle it on my own as seemed to be more a quite specific and interesting issue to try to find a solution to - particularly since I wanted to not only spread asynchronous tasks by queues, but also to make it dependent on loaded file sizes to keep it balanced.

Adding a code to simply download a file by URL is somewhat trivial and I wouldn’t want to litter this post with it, but I would like to give some attention to the code on how to make (with javascript) an abstract pool for weighted asynchronous tasks.

Pool interface:

Pool implementation:

Queue implementation:

Potentially Queue.add can be rewritten with async/await and looping inside instead of a promises chain (stopping a cycle is more simple than a promises chain, but it also has its own positives and negatives beyond the scope of this post).

And a result of the tasks execution:

$ node tasks.js
Queue #1: task is started
Queue #2: task is started
Queue #3: task is started
Queue #4: task is started
Finishing task #4
Queue #4: task is finished
Queue #4: task is started
Finishing task #1
Queue #1: task is finished
Queue #1: task is started
Finishing task #6
Queue #1: task is finished
Queue #1: task is started
Finishing task #2
Queue #2: task is finished
Queue #2: task is started
Finishing task #3
Queue #3: task is finished
Queue #3: task is started
Finishing task #5
Queue #4: task is finished
Finishing task #9
Queue #3: task is finished
Finishing task #8
Queue #2: task is finished
Queue #2: task is started
Finishing task #10
Queue #2: task is finished
Finishing task #7
Queue #1: task is finished
All tasks are done

Many kudos for text review & comments to David Lorbiecke.

--

--

Sergei
Pipedrive R&D Blog

Software Engineer. Senior Backend Developer at Pipedrive. PhD in Engineering. My interests are IT, High-Tech, coding, debugging, sport, active lifestyle.