0

I have a queue of tasks that will run in Javascript, some are ajax calls, some are simple dom changes, so the time each one takes varies, but they need to run in order and wait their turn.

So for example, imagine this needs to happen:

Task 1: Takes 1s to complete
Task 2: Takes 0.5s to complete
Task 3: Takes 0.3s to complete
Task 4: Takes 0.75s to complete

Task 2 shouldn't run until task 1 is done (1s), etc.

I've tried using a foreach loop with a callback, but the faster tasks run before the slow ones, even if they are at the end of the queue. Here is a fiddle showing it in action.

https://jsfiddle.net/omp5cdm1/

var someArray = [1000, 500, 300, 750];

someArray.forEach(function(item, i) {
    asyncFunc(item, function(item) {
       console.log(i)
    });
});


function asyncFunc( item, callback ) {
	setTimeout(function() { 
       document.getElementById("output").innerHTML += item + ', ';
       callback();
  }, item);
}
Needed output: 1000, 500, 300, 750
<br>
<div id="output">Actual output: 

</div>

Needed output order: 1000, 500, 300, 750

Actual output order: 300, 500, 750, 1000

Edit: I need to make it work on IE10+ too, so can't use es6 :(

7
  • Clarify the sense in which they need to run "in order": do the callback functions need to execute in succession, or do the asynchronous functions themselves need to run in succession? Commented Aug 3, 2017 at 2:42
  • The tasks make changes to the dom, and they are all interlinked, so need to happen in strict succession, so imagine the first task takes 10s to complete, that means the next task (second in the array) shouldn't run until the first one is completed (so after 10s), and so on. I hope this makes more sense! Commented Aug 3, 2017 at 2:44
  • Use setInterval to continuous checking for previous task is finished and then start new one Commented Aug 3, 2017 at 2:45
  • 2
    Can you post code that actually resembles your real-world scenario? I'm guessing your actual scenario does not revolve around use of setTimeout, does it, but rather uses callbacks? The odd behavior of your example is likely more due to the way you've tried to simplify the code. Anyhow, if you have a bunch of async tasks to do in series, the simplest way is to promisify them and just create the chain of events using .then(). There are ES5 promise libraries, such as Bluebird, that use ES6-compatible syntax. Commented Aug 3, 2017 at 2:49
  • Indeed, the real world scenario is much bigger so I tried to simplify it with timeouts to illustrate different completion timings. Some tasks will take 1s, some 0.1s, so it does seem like the only solution to make them run in a series is with a promise library. I was hoping for a light solution without libraries, but oh well Commented Aug 3, 2017 at 2:53

1 Answer 1

2

Your 'asyncFunc' isnt actually asynchronous: it is called for each item in someArray immediately and is acting like a sleep sort.
This example will wait for the timeout before calling the function on the next item in the array.

var arr = [1000, 500, 300, 750];

function next() {
  var item = arr.shift();
  if (typeof item === 'undefined') return;
  document.getElementById("output").innerHTML += item + ', ';
  asyncFunc(item, next);
}
function asyncFunc(item, callback) {
  setTimeout(callback, item);
}
next();
<div id="output"></div>

Sign up to request clarification or add additional context in comments.

1 Comment

It may be a good idea to also show how this can be done using async.series from async.js

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.