Asa Carter
Asa Carter

Reputation: 2225

setTimeout not pausing iterations in loop

I am trying to iterate through a list of orders, pausing each one for 3 seconds. Then once complete, start again in a loop.

In the snippet below, if the loop is enabled it seems to be starting the loop again before the first loop has completed.

Also the 3 second pause between each call to display_notification is not working.

start: function() { 
    $.each(this.orders, function(index, order) {
        setTimeout(function() {
            console.log ('show notification');
            recentlyApp.display_notification(order);
        }, index * 3000);
    });
    if (this.settings.loop) {
        this.start();
    }
},
display_notification: function(order) {
    console.log(order);
}

Upvotes: 1

Views: 87

Answers (2)

Buzinas
Buzinas

Reputation: 11733

As soon as you're already using jQuery, you can create a plugin to loop through an array in an interval.

Example:

// timer function that loops through an array with in a given interval
$.timer = function (list, callback, time/*, onFinish, index*/) {
  var onFinish = arguments.length > 3 ? arguments[3] : void 0,
      index = arguments.length > 4 ? arguments[4] : 0;
  
  if (index < list.length) {
    list.__timed = setTimeout(function() {
      callback.call(this, index, list[index]);
      $.timer(list, callback, time, onFinish, ++index);
    }, time);
  }
  else if (onFinish){
    onFinish.call(this);
  }

  return {
    cancel: function() {
      if (list.__timed !== void 0) {
        clearTimeout(list.__timed);
        delete list.__timed;
      }
    }
  };
}

// usage
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

var timer = $.timer(arr, function (index, item) {
  document.querySelector('div').insertAdjacentHTML('beforeend', '<div>' + item + '</div>');
}, 3000, function() {
  document.querySelector('div').insertAdjacentHTML('beforeend', '<div>Finished</div>');
});

// cancelling the loop
$('button').click(function(e) {
  timer.cancel();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<button>Cancel timer</button>

So, in your scenario, it would be something like this:

start: function() { 
  $.timer(this.orders, function(index, order) {
    console.log('show notification');
    recentlyApp.display_notification(order);
  }, 3000, this.settings.loop ? this.start : void 0);
},
display_notification: function(order) {
  console.log(order);
}

UPDATE

Now, the $.timer is returning an object with the cancel method, so you can cancel the loop at anytime by calling .cancel();.

I've created a __timed property into the array to always get the last setTimeout executed, so when you call the cancel method, it calls the clearTimeout for what it was going to call next.

Upvotes: 1

Quentin
Quentin

Reputation: 944545

You're calling this.start() as soon as you've finished the loop that sets up the timeout functions.

Either track the last value of index and use it to set a timeout on the call to start() or put the call to start() in the last timed out function you set going in the loop.

Upvotes: 1

Related Questions