顺序运行多个setIntervals

时间:2014-03-14 18:02:25

标签: javascript asynchronous

我试图运行多个setInterval()但我在执行此操作的异步方面遇到了问题。

这个例子与我试图实现的几乎相同:

var labels = ["Bacon", "Beer", "Steak"];
var second, timer;
labels.forEach(function(label){
    second = 0;
    timer = setInterval(function(){
        console.log(label + ' is awesome ' + second);
        if(second === 10) {
            clearInterval(timer);
        }
        second++;
    }, 1000);
});

由于setInterval是异步的,因此三个间隔并行运行并且正在弄乱间隔:

  

培根非常棒0

     

啤酒真棒1

     

牛排很棒2

     

啤酒很棒3

     

培根很棒4

     

牛排很棒5

     

培根非常棒6

     

啤酒很棒7

     

牛排很棒8

     

培根很棒9

     

啤酒很棒10

     

啤酒很棒11

     

培根非常棒12

     

啤酒很棒13

     

培根很棒14

     

培根非常棒15

     

啤酒很棒16

     

啤酒很棒17

     

培根很棒18

     

培根很棒19

     

啤酒很棒20

     

啤酒很棒21

     

培根很棒22

     

培根很棒23

     

...

我想知道如何强制执行某种队列,以便第一个间隔运行它,然后当10秒钟时,下一个setInterval被执行?

我已经快速尝试了async.js库,但我找不到合适的控制流程。

4 个答案:

答案 0 :(得分:2)

这对我来说很适合练习一些OO风格的Javascript:)

    function Timer(name) {
    var self = this;
    this.name = name;
    this.count = 0;
    this.x = setInterval(function () {
        if (self.count++ == 9) {
            clearInterval(self.x);
        }
        console.log(self.name + ' ' + self.count + ' is awesome');
    }, 1000);
}



var labels = ["Bacon", "Beer", "Steak"];
labels.forEach(function (label) {
    new Timer(label);
});

Demo

答案 1 :(得分:2)

我做了一个名为`callQueue'调用一个充满函数的数组按顺序调用一定次数

<强>用法

第一个参数是函数数组,第二个参数是它们应被调用的次数,第三个参数是调用之间的时间。

callQueue([

function () {
    isAwesome('bacon');
},

function () {
    isAwesome('beer');
},

function () {
    isAwesome('steak');
}], 10, 1000);

功能

function callQueue(queue, times, timeBetween) {
    var i = 0;
    k = 0;
    queue.forEach(function (func) {
        for (k = 0; k < times; k += 1) {
            alert(i * timeBetween);
            i += 1;
            setTimeout(func, (i * timeBetween));
        }
    });
};

演示:http://jsfiddle.net/howderek/L5nhU/

答案 2 :(得分:2)

你可以例如在没有循环的情况下使用setTimeout,并从函数中选择正确的标签。

var labels   = ["Bacon", "Beer", "Steak"],
    steps    = 10,
    total    =  0,
    step     =  0,
    sequence =  0,
    label    = labels [0];

(function fn (){
    if (step === steps && sequence === labels.length - 1) {
        return;
    } else if(step === steps) {
        label = labels [++sequence];
        step  = 0;
    }  

    console.log(label + ' is awesome ' + total);

    step++;
    total++;
    setTimeout (fn, 1000)
})();

Fiddle

或者例如保持循环并使用索引和步数作为超时乘数,以相应地延迟其他超时。

var labels = ["Bacon", "Beer", "Steak"],
    steps = 10,
    total = 0;
labels.forEach(function(label, index){
    var step = 0;
        setTimeout (function fn (){
            if(step === steps) {
                return;
            }

            console.log(label + ' is awesome ' + total);

            step++;
            total++;
            setTimeout (fn, 1000)
        },( (steps + 1)* index ) * 1000);
});

Fiddle

或者将setInterval包裹在setTimeout中。

var labels = ["Bacon", "Beer", "Steak"];
labels.forEach(function(label, index){
    setTimeout (function () {
           var second = 0;
           var timer = setInterval(function(){
                console.log(label + ' is awesome ' + second);
                if(second === 10) {
                    clearInterval(timer);
                }
                second++;
            }, 1000);
    },index * 11 * 1000);
});

Fiddle

所有产品

Bacon is awesome 0
Bacon is awesome 1
Bacon is awesome 2
Bacon is awesome 3
Bacon is awesome 4
Bacon is awesome 5
Bacon is awesome 6
Bacon is awesome 7
Bacon is awesome 8
Bacon is awesome 9
Beer is awesome 0
Beer is awesome 1
Beer is awesome 2
Beer is awesome 3 
... 

答案 3 :(得分:0)

在您拨打setIntervalsetTimeout之后,您已经掌握了浏览器;通过的时间并不保证是准确的,并且执行多个回调的顺序并不保证是准确的 - 并且通常不会成为。

如果要强制执行顺序,使用setTimeout代替setInterval将使您有机会决定每次回调完成时会发生什么。

这是一个小提琴首先迭代培根,然后是啤酒,然后是牛排:http://jsfiddle.net/q96Vc/

这是一个一个接一个地显示每个标签,直到30秒为止:http://jsfiddle.net/DtbZ6/1/

您甚至可以扩展其中任何一个示例,以使用三个单独的setTimeout调用,这些调用不会被重复,直到之前的三个调用都已执行,这意味着三个调用的顺序不一样,但它们永远不会重叠。