4

I got async function:

var func = function  (arg, next) {
    var milliseconds = 1000;
    setTimeout(function(){
        console.log (arg);
        next()
    }   , milliseconds);
}

And array:

var arr = new Array();
arr.push (0);
arr.push (1);

console.log(arr);

I want to use func for every item of my array arr:

func(arr[0], function(){
    func(arr[1], function(){
        console.log("finish");
    })
})

Ok for array consisted of 2 elements, but if I got array of 1000 elements how to use func for every item in arr?

How to do it in cycle?

4
  • 1
    sitepoint.com/javascript-large-data-processing Commented Jul 25, 2013 at 14:01
  • are you talking about a foreach loop? Commented Jul 25, 2013 at 14:03
  • arr.forEach(func(this)); would this work? Commented Jul 25, 2013 at 14:12
  • @TraeMoore: No, definitely not. Did you try it? Commented Jul 25, 2013 at 14:15

7 Answers 7

3
var arrayFunc = function(array) {
  if (array.length > 0) {
    func(array[0], function() { arrayFunc(array.slice(1)); });
  }
}

This will run your function with the first element in the array, and then have the continuation function take the rest of the array. So when it runs it will run the new first element in the array.

EDIT: here's a modified version that doesn't copy the array around:

var arrayFunc = function(array, index) {
  if (index < array.length) {
    func(array[index], function() {
      var newI = index + 1;
      arrayFunc(array, newI);
    });
  }
}

And just call it the first time with an index of 0.

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

6 Comments

I need to start thinking faster, this is the exact same solution I got to! :)
Won't array.slice create a new array? This would lead to O(n^2) memory consumption.
Good catch. For small arrays it should be fine. If dealing with large amounts of data then yes, it could be made better. Edited to provide that option as well.
arr.forEach(func(this)); would this work? sorry, wrong comment section
The new function doesn't work; it will forever invoke func with the same index.
|
0

While your approach is valid, it's not possible to use it if you have an uncertain number of calls, since every chain in your async command is hardcoded.

If you want to apply the same functionality on an array, it's best to provide a function that creates an internal function and applies the timeout on it's inner function:

var asyncArraySequence = function (array, callback, done){
  var timeout = 1000, sequencer, index = 0;

  // done is optional, but can be used if you want to have something
  // that should be called after everything has been done
  if(done === null || typeof done === "undefined")
    done = function(){}

  // set up the sequencer - it's similar to your `func`
  sequencer = function(){
    if(index === array.length) {
      return done();      
    } else {
      callback(array[index]);
      index = index + 1;
      setTimeout(sequencer, timeout);
    }
  };
  setTimeout(sequencer, timeout);
}

var arr = [1,2,3];
asyncArraySequence(arr, function(val){console.log(val);});

Comments

0

A simple asynchronous loop:

function each(arr, iter, callback) {
    var i = 0;
    function step() {
        if (i < arr.length)
            iter(arr[i++], step);
        else if (typeof callback == "function")
            callback();
    }
    step();
}

Now use

each(arr, func);

Comments

0

You may try arr.map

var func = function  (arg, i) {
    var milliseconds = 1000;
    setTimeout(function(){
        console.log (arg);
    }, milliseconds*i);
}

var arr = new Array();
arr.push (0);
arr.push (1);

arr.map(func);

Demo and Polyfill for older browsers.

Update : I thought the OP wants to loop through the array and call the callback function with each array item but I was probably wrong, so instead of deleting the answer I'm just keeping it here, maybe it would be helpful for someone else in future. This doesn't answer the current question.

3 Comments

What would you map to? Makes no sense here.
Sorry, I didn't get it, isn't it looping the array and calling the function ?
map doesn't help here. He doesn't want to call func() on each element in the array immediately. He wants to call it on the first element, and pass to that a function that calls it on the second, etc.
0

Thanx, @Herms. Working solution:

var arrayFunc = function(array) {
  if (array.length > 0) {
    func(array[0], function() {arrayFunc(array.slice(1)); });
  }
  else
  {
    console.log("finish");
  }
}
arrayFunc(arr);

Comments

0

A simple solution would be:

var fn = arr.reduceRight(function (a, b) {
  return func.bind(null, b, a);
}, function() {
  console.log('finish');
});

fn();

demo: http://jsbin.com/isuwac/2/


or if the order of func's parameters could be changed to receive the next callback as the first parameter, it could be as simple as:

['a', 'b', 'c'].reduceRight(func.bind.bind(func, null), function (){
  console.log('finish');
})();

demo: http://jsbin.com/ucUZUBe/1/edit?js,console

Comments

-1

You can loop through the array

for(var i = 0; i < arr.length; i++){
    func(arr[i], function(){...});
}

1 Comment

That won't do them in sequence like he wants. It would start them all immediately, instead of starting the next after the previous was done.

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.