Polyfill for Async.series(tasks, callback)

The series method was quite a different one when we compared it to other sequential call stacks. The series method will take two arguments one is an array of functions and another one is the finalCallback which is optional to call with the first occurred error and obtained results until then.

 

async.series( 
  [fn-1(callback), fn-2(callback), ... fn-n(callback)], 
  finalCallback( error, results ){ ... }
);

Now will talk about the implementation. We can solve this problem by making Asyncify each task from the tasks array. This way, we can extract the result from each task, review for errors, and move to the next task. Let’s move to the code implementation.

Asyncify a task


function Asyncify(task) {
  return new Promise((resolve, reject) => {
    task((error, result) => (error ? reject(error) : resolve(result)));
  });
}

That’s all we have completed with the implementation, and we need to use this method to queue up the tasks in a sequential way of execution.

async function series(tasks, finalCallback) {
  const allResults = [];
  for (let i = 0; i < tasks.length; i++) {
    try {
      allResults.push(await Asyncify(tasks[i]));
    } catch (error) {
      finalCallback(error, allResults);
      break;
    }
  }
  console.log(allResults);
  finalCallback(null, allResults);
}

This solution is based on Promise API, and you can execute the below code in the browser console for quick analysis. And we can also implement a recursive-based solution and will look into it in our next post.
The full spec you can read from https://caolan.github.io/async/v3/docs.html#series.

Now, add some sample tasks to test and see how this works.

const sampleTasks =  [ function (callback) { setTimeout(function () { console.log("1"); callback(null, "one"); }, 200); }, function (callback) { setTimeout(function () { console.log("2"); callback(null, "two"); }, 100); }, function (callback) { setTimeout(function () { console.log("3"); callback(null, "three"); }, 90); }, function (callback) { setTimeout(function () { console.log("4"); callback(Error("some error")); }, 10); }, function (callback) { setTimeout(function () { console.log("5"); callback(null, "five"); }, 1000); }, ];

function onSeriesCompleted(error, results) {
  console.log("Error stack", error);
  console.log("Results of successfully executed tasks", results);
}

function Asyncify(task) {
  return new Promise((resolve, reject) => {
    task((error, result) => (error ? reject(error) : resolve(result)));
  });
}

async function series(tasks = [], finalCallback) {
  const allResults = [];
  for (let i = 0; i < tasks.length; i++) {
    try {
      allResults.push(await Asyncify(tasks[i]));
    } catch (error) {
      finalCallback?.(error, allResults);
      return; //remove if you want continue even after error
    }
  }
  finalCallback?.(null, allResults);
}

series(sampleTasks, onSeriesCompleted);

Output

Leave a Reply

Your email address will not be published. Required fields are marked *