Reputation: 4807
I have a Array.each function that I need pause for 5 seconds every time the loop has run through 25 times.
Array.each(response.data, function(thing, index){
sendEmail(thing.id,sku,thing.email);
});
I've tried various methods, but it always just calls the sendEMail function without a delay. Does anyone know how to do this?
The loop may run from 15 to 500 times, depending on the data sent to it.
thanks.
Mootools 1.4.5
Upvotes: 1
Views: 434
Reputation: 6499
I would split your ploblem in two different subproblem, you want a way to group an Array by X items:
Array.implement('paginate', function(count){
var result = [], pageIndex = -1
for(var i=0, max = this.length; i<max; i++){
if (i%count==0){
pageIndex++
result.push([])
}
result[pageIndex].push(this[i])
}
return result;
});
then you want to process each 'page' of the Array and wait Y seconds before doing anything with the rest of the data.
function process(data, index, delay){
workondata(data[index]);
if( data.length-index >1 ) setTimeout(
function(){
process(data, index +1, delay)
},
delay
);
}
So I believe something like this: http://jsfiddle.net/kentaromiura/SmyU8/ would do the job.
Upvotes: 0
Reputation: 26165
I'd go for a more generic chunking method.
Array.implement({
chunkEach: function(offset, count, delay, fn, bind){
// get a chunk
var newOffset = offset + count,
chunk = this.slice(offset, newOffset),
ii = 0,
len = chunk.length;
if (!len)
return this;
// loop the chunk supporting natural index.
for (; ii< len; ++ii)
fn.call(bind, chunk[ii], offset + ii);
// move pointer and self call
if (newOffset < this.length)
this.chunkEach.delay(delay, this, [newOffset, count, delay, fn, bind]);
// pointless chaining return as its async.
return this;
}
});
use, eg loop array of email addresses at chunks of 15 with a 2 second pause, keeping scope of function to an imaginary object with an options property:
list.chunkEach(0, 15, 2000, function(el, index){
console.log(this.options);
new Element('div[html='+index + '. ' + el +']').inject(o);
}, this);
see http://jsfiddle.net/dimitar/aYwab/
its rough - lacks checks for arguments and stuff but it will do what you want.
there may be question as to the responsibility for resolving the delay here. you are sending emails, presumably via ajax. an ambiguous delay is not scalable.
you should look at making the sendEmail
function chainable - simply pass the array and index into it, and if index is less than the array length - 1, call sendEmail
again from the onSuccess
with the next index. this also allows you to break or retry if last send fails.
also, you can use Promises.
Upvotes: 1
Reputation: 2619
You won't be able to stop the loop iteration part-way through the loop unless Array.each
allows you to quit out early from within the passed in callback and allows you to resume from an arbitrary index. You would still then need to have logic wrapped around it to handle the pausing.
The alternative is to roll your own.
var eachWithPause = function( iterable, iterations, timeout, fn, ctx ) {
// Sets up a callback to be passed back to the caller, allowing them
// to cancel the `setTimeout` call created within `loop`.
var timeoutID = 0;
var cancel = function() {
clearTimeout( timeoutID );
};
// `loop` will run the desired number of iterations, or iterate through
// the remainder of the `iterable`, whichever comes first. If there are
// still elements left after it is done, it will `setTimeout` for the
// desired amount of time.
var index = 0, l = iterable.length;
var loop = function() {
for ( var i = 0; i < iterations && index < l; ++i, ++index ) {
fn.call( ctx, iterable[ index ], index, iterable );
}
if ( index < l ) {
timeoutID = setTimeout( loop, timeout );
} else {
timeoutID = 0;
}
};
loop();
return cancel;
};
The only thing interesting I'm doing here is returning a cancel
function that will provide the caller with a way to call clearTimeout
on an ever-changing setTimeout
that it doesn't have access to.
You would then have something similar to
var cancel = eachWithPause(response.data, 5, 5000, function(thing, index) {
sendEmail(thing.id, sku, thing.email);
});
and if you ever needed to cancel this operation, you could then simply cancel()
it.
Upvotes: 1