DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Creating Async Task Runner with Concurrency in JavaScript
Bidisha Das
Bidisha Das

Posted on

Creating Async Task Runner with Concurrency in JavaScript

Let us consider we need to create an aync task runner in javascript with the following constraint:

  1. The task runner should have a set of tasks that will be pushed to it,
  2. Each of these tasks will be some async operation,
  3. The task runner should also ensure that at a single point of time only a given number of tasks can perform, and other tasks keep on waiting unless their turn comes.

Let's code out the solution first

class Runner{
      constructor(concurrency=1){
          this.concurrency = concurrency;
          this.waitList = [];
          this.count = 0;
          this.currentQ = [];
      }
      push(task){
         this.waitList.push(task);
         this.run();
      }
      run(){
         let current = this;
         if(this.count<this.concurrency){
            this.count++;
            if(this.waitList.length>0){
               let task = this.waitList.shift();
               let id = task.id;
               this.currentQueue.push(id);
               this.showRunningTasks();
               let done = function(){ 
       this.currentQueue.splice(this.currentQueue.indexOf(id),1);
                  this.showRunningTasks();
                  this.count = this.count - 1;
                  this.run();
               }.bind(current);
               task.task(done);
            }
         }
      }

      showRunningTasks(){
         let existingQueue = this.currentQueue.join(", ");
         document.getElementId("running").innerHTML = existingQueue;
      }
}

Enter fullscreen mode Exit fullscreen mode

Image description

Let's understand this piece of code line by line.

  1. Initially we pass the concurrencyflag indicating how many tasks can run concurrently. The waitList is used for making a wait list of tasks, which will wait unless the queue referred to as currentQueue is empty. The count variable is initialised to count the number of concurrent tasks at a moment.

  2. The push method is used to push a task to waitList, and we then execute the run method.This simply indicates that the tasks need to be run if the queue is empty

  3. The run method is interesting. First it preserves the context of the task by the virtue of first line denoted as let current = this

  4. Next, we check for the concurrency and if the waitList has elements, we simply,

  • push the task id to the currentQueue,
  • display the current running tasks via the method showRunningTasks,
  • in the inner donemethod, which will be taken as a callback in tasks, we simply remove the task with the id from current
    queue
    , reduce the count to reduce the total number of concurrent tasks,
  • In the end, we recursively call the run() method to run the current function. Note, here the context remains same.
  • Lastly we bind this function to the current context.
  • We pass this function to task.task function.

Let's now see how this method can be used

Use the following code snippet to see the result.

let runner = new Runner(3);
let task1 = {
  id: 1,
  task: function(done) {
    setTimeout(function() {
      console.log("Task 1");
      done();
    }, 3000)
  }
}

let task2 = {
  id: 2,
  task: function(done) {
    setTimeout(function() {
      console.log("Task 2");
      done();
    }, 5000)
  }
}

let task3 = {
  id: 3,
  task: function(done) {
    setTimeout(function() {
      console.log("Task 3");
      done();
    }, 4000)
  }
}

let task4 = {
  id: 4,
  task: function(done) {
    setTimeout(function() {
      console.log("Task 4");
      done();
    }, 9000)
  }
}

runner.push(task1);
runner.push(task2);
runner.push(task3);
runner.push(task4);
Enter fullscreen mode Exit fullscreen mode

You will see the result on the screen as Task 1, Task 3, Task 2, Task 4, which is expected.

Top comments (4)

Collapse
 
artydev profile image
artydev • Edited on

Great thank you.
Perhaps could you be interested at the Communicating Sequential Process Cispy
Here is a little demo CspTaskRunner

Regards

Collapse
 
caihai123 profile image
caihai123

插δΈͺ眼

Collapse
 
kumarkalyan profile image
Kumar Kalyan

Amazing article. Wonderfully explained :)

Collapse
 
officialbidisha profile image
Bidisha Das

Thank you so much.

Hey 😍

Want to help the DEV Community feel more like a community?

Head over to the Welcome Thread and greet some new community members!

It only takes a minute of your time, and goes a long way!