1

我有一个 Array.each 函数,每次循环运行 25 次时,我需要暂停 5 秒。

Array.each(response.data, function(thing, index){
    sendEmail(thing.id,sku,thing.email);
});

我尝试了各种方法,但它总是毫无延迟地调用 sendEMail 函数。有谁知道如何做到这一点?

循环可能会运行 15 到 500 次,具体取决于发送给它的数据。

谢谢。

Mootools 1.4.5

4

3 回答 3

1

Array.each除非允许您从传入的回调中提前退出并允许您从任意索引恢复,否则您将无法在循环的中途停止循环迭代。您仍然需要将逻辑包裹在它周围来处理暂停。

另一种方法是自己动手。

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;
};

我在这里做的唯一有趣的事情是返回一个cancel函数,该函数将为调用者提供一种调用它无法访问clearTimeout的不断变化的方法。setTimeout

然后你会有类似的东西

var cancel = eachWithPause(response.data, 5, 5000, function(thing, index) {
  sendEmail(thing.id, sku, thing.email);
});

如果您需要取消此操作,您可以简单地取消cancel()它。

于 2013-02-15T05:11:14.383 回答
1

我会选择更通用的分块方法。

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;
    }
});

使用,例如,以 15 个块为单位循环电子邮件地址数组,并暂停 2 秒,将功能范围保持在具有选项属性的虚构对象中:

list.chunkEach(0, 15, 2000, function(el, index){
    console.log(this.options);
    new Element('div[html='+index + '. ' + el +']').inject(o);
}, this);

http://jsfiddle.net/dimitar/aYwab/

它的粗糙 - 缺乏对参数和东西的检查,但它会做你想做的事。

在这里解决延迟的责任可能存在疑问。您正在发送电子邮件,大概是通过 ajax。模棱两可的延迟是不可扩展的。

您应该考虑使sendEmail函数可链接 - 只需将数组和索引传递给它,如果索引小于数组长度 - 1,sendEmail则从onSuccess下一个索引再次调用。如果上次发送失败,这也允许您中断或重试。

此外,您可以使用 Promises。

于 2013-02-16T14:01:00.640 回答
0

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.

于 2013-02-16T16:40:37.150 回答