Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

90
Views
Task Runner in Javascript

I have a list of tasks and all these tasks need to be executed only after all the dependencies are resolved for each task. I am struggling to figure out a way to finish running all the tasks in optimal time.

// Each node is a async job, illustrated by setTimeout.
// A and C can run at the same time.
// D, needs to wait for A and C to be done.
// E needs to wait for A and D to be done.

function runTasks(tasks) {
 // run tasks
}

// Sample of tasks
var tasks = {
  'a': {
    job: function (finish) {
      setTimeout(function () {
        console.log('a done');
        finish();
      }, 500);
    },
  },
  'c': {
    job: function (finish) {
      setTimeout(function () {
        console.log('c done');
        finish();
      }, 200);
    },
    dependencies: [],
  },
  'd': {
    job: function (finish) {
      setTimeout(function () {
        console.log('d done');
        finish();
      }, 100);
    },
    dependencies: ['a','c'],
  },
  'e': {
    job: function (finish) {
      setTimeout(function () {
        console.log('e done');
        finish();
      }, 200);
    },
    dependencies: ['a', 'd'],
  },
};
about 4 years ago · Juan Pablo Isaza
3 answers
Answer question

0

Something like this might be possible, I have changed the jobs to async methods and I keep track of them being resolved or not.

This code does not check for errors within the job or for circular dependencies.

Output of the script:

b done
a done
c done
e done
done

Code:

const runTasks = async tasks => {
  const taskArray = Object.entries(tasks)
  const resolved = {}

  while (taskArray.length) {
    const tasksToExecute = []
    for (const task of taskArray) {
      const dependencies = task[1].dependencies || []
      if (dependencies.length === 0 || dependencies.every(dependency => resolved[dependency] || false)) {
        tasksToExecute.push(task)
      }
    }

    await Promise.all(tasksToExecute.map(t => t[1].job()))
    tasksToExecute.forEach(t => {
      resolved[t[0]] = true
      taskArray.splice(taskArray.indexOf(t[0]), 1)
    })
  }
}

const tasks = {
  a: {
    job: async function () {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log("a done")
          resolve()
        }, 500)
      })
    },
  },
  c: {
    job: async function () {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log("c done")
          resolve()
        }, 200)
      })
    },
    dependencies: ["a", "b"],
  },
  b: {
    job: async function () {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log("b done")
          resolve()
        }, 100)
      })
    },
    dependencies: [],
  },
  e: {
    job: async function () {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log("e done")
          resolve()
        }, 200)
      })
    },
    dependencies: ["c", "b"],
  },
}

runTasks(tasks).then(r => console.log("done"))
about 4 years ago · Juan Pablo Isaza Report

0

A simple recursive dependencies evaluation with caching of results will do. Use Promise.all to wait for all dependencies:

function runTasks(tasks) {
  const promises = {};
  function runTask(name) {
    const {dependencies, job} = tasks[name];
    return promises[name] ??= Promise.all(dependencies.map(runTask)).then(job);
  }
  return Promise.all(Object.keys(tasks).map(runTask));
}

Maybe use Promise.allSettled instead of Promise.all in the final return statement.

If you need to detect circular dependencies, you can use

…
  const circular = Promise.reject(new Error("circular dependency"));
  circular.catch(() => { /* ignore */ }); // prevent unhandled rejection
  function runTask(name) {
    const {dependencies, job} = tasks[name];
    if (promises[name] != null) return promises[name];
    promises[name] = circular;
    return promises[name] = Promise.all(dependencies.map(runTask)).then(job);
  }
…
about 4 years ago · Juan Pablo Isaza Report

0

You can start parallel promises which can be started.

  1. Start all independent task first which has no dependencies
  2. After completing independent tasks store in map/set
  3. Then filter a new set of tasks using the complete set repeat steps.

const wait = (ms, task) =>
  new Promise((resolve) =>
    setTimeout(() => {
      console.log(`${task} done`);
      resolve();
    }, ms)
  );

const tasks = {
  a: {
    job: () => wait(500, "A"),
    dependencies: [],
  },
  c: {
    job: () => wait(500, "C"),
    dependencies: [],
  },
  d: {
    job: () => wait(500, "D"),
    dependencies: ["a", "c"],
  },
  e: {
    job: () => wait(500, "E"),
    dependencies: ["a", "d"],
  },
};

const run = async () => {
  const completed = new Set();
  const keys = Object.keys(tasks);
  const runTasks = async (pendingTasks) => {
    const promises = pendingTasks.map((key) => tasks[key].job());
    await Promise.all(promises);
    pendingTasks.forEach((key) => completed.add(key));
  };

  const runner = async () => {
    const pendingTasks = keys.filter((key) => {
      if (!completed.has(key)) {
        const { dependencies } = tasks[key];
        return dependencies.every((dependency) => completed.has(dependency));
      }
      return false;
    });
    if (pendingTasks.length !== 0) {
      await runTasks(pendingTasks);
      return runner();
    }
  };

  await runner();
};

run();

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!