2

I have an array of function with async method inside it.I want to create a function which takes the array of function and execute the function in sequential order.I am not sure how to achieve it.Thanks for help.The functions are not async in nature.Its the method inside each functions

Example.

function task1() {
  console.log('task1:started');
  setTimeout(function() {
    console.log('task1:finished');
  }, 5000);
}

function task2() {
  console.log('task2:started');
  setTimeout(function() {
    console.log('task2:finished');
  }, 5000);
}

function runner(tasks) {
  // help with implementation needed
  console.log('Desired Output:');
  console.log('task1: started');
  console.log('task1: finished');

  console.log('task2: started');
  console.log('task2: finished');
}
marionebl
  • 3,342
  • 20
  • 34
nandanself
  • 835
  • 8
  • 21
  • 1
    Possible duplicate of [Node.js: How to run asynchronous code sequentially](https://stackoverflow.com/questions/27724323/node-js-how-to-run-asynchronous-code-sequentially) – suraj.tripathi Feb 25 '18 at 17:28
  • 2
    Without taking a callback or returning a callback, you'll have a hard time to know when such a task is finished – Bergi Feb 25 '18 at 17:31
  • @suraj.tripathi . I can't use .then property on functions because they are not async in nature.its the method inside each function which is async in nature – nandanself Feb 25 '18 at 17:33
  • 1
    @MarutiNandan you'll need to rewrite those functions to either take a callback or return a promise. Is that an option? – Mark Feb 25 '18 at 17:36
  • @Mark_M I can't modify those functions – nandanself Feb 25 '18 at 17:37
  • 2
    If these functions don't have any way of signaling when they are finished, there's not much you can do. This seems unusual since almost all async functions have some way - a callback, or promise - of letting you know they are finished. – Mark Feb 25 '18 at 17:38
  • @MarutiNandan any specific reason for not modify those functions – suraj.tripathi Feb 25 '18 at 17:56
  • @MarutiNandan See the answer below - without providing a hook into completed computation of your tasks you won't be able to orchestrate them (e.g. run in sequence) in any way. – marionebl Feb 25 '18 at 18:33

1 Answers1

2

Classic answer

You'll have to accept callbacks to achieve this, e.g.

runner([task1, task2], function() {
  console.log('tasks done!');
})

function task1(cb) {
  console.log('task1:started');
  setTimeout(function() {
    console.log('task1:finished');
    cb();
  }, 100);
}

function task2(cb) {
  console.log('task2:started');
  setTimeout(function() {
    console.log('task2:finished');
    cb();
  }, 100);
}

function runner(tasks, cb) {
  if (!tasks.length) {
    return cb();
  }

  let index = 0;

  function run() {
    var task = tasks[index++]

    task(index === tasks.length ? cb : run);
  }

  run();
}

Using async.waterfall

async.waterfall([task1, task2], function() {
  console.log('tasks done!');
})

function task1(cb) {
  console.log('task1:started');
  setTimeout(function() {
    console.log('task1:finished');
    cb();
  }, 100);
}

function task2(cb) {
  console.log('task2:started');
  setTimeout(function() {
    console.log('task2:finished');
    cb();
  }, 100);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/async/2.6.0/async.js"></script>

Promise-based implementation

runner([task1, task2]).then(() => {
  console.log('tasks done')
})

function task1(cb) {
  return new Promise(resolve => {
    console.log('task1:started');
    setTimeout(function() {
      console.log('task1:finished');
      resolve();
    }, 200);
  });
}

function task2(cb) {
  return new Promise(resolve => {
    console.log('task2:started');
    setTimeout(function() {
      console.log('task2:finished');
      resolve();
    }, 100);
  });
}

function runner(tasks, cb) {
  return tasks.reduce((job, task) => job.then(task), Promise.resolve());
}
marionebl
  • 3,342
  • 20
  • 34
  • 1
    No need to make `run`, `next` and the anonymous callback three separate functions. – Bergi Feb 25 '18 at 17:58
  • 1
    Not really, imo. You've also duplicated a lot of the code, like the `tasks.length` check. Also why would `index++` *not* be inside `next`? – Bergi Feb 25 '18 at 18:06
  • You are entitled to your opinion, I won't engage in discussion of actual or perceived stylistic issues. You are free to provide a superior implementation. – marionebl Feb 25 '18 at 18:09
  • I didn't mean to start a discussion either, I just wanted to give a tip and a reason why I didn't upvote despite the otherwise great answer :-) – Bergi Feb 25 '18 at 18:14
  • 1
    @Bergi: Revisited the callback example and optimized for brevity. – marionebl Feb 25 '18 at 18:28