jQuery - 一次触发两次setInterval()的函数?

时间:2012-09-20 16:05:14

标签: jquery setinterval

我有一个jQuery函数,使用setInterval()来慢慢输入一个短语 - 就像短语“string one”一样,每个字符将在设定的毫秒数后打印到屏幕上。

问题在于,在我的代码中,我有一个接一个地调用函数,并且它们重叠,因为setInterval()似乎没有停止正常的代码流。很难解释,here's my jsFiddle表明会发生什么。

这是我的功能:

function type(text) {
    if(intv == null) {
        var textArray = text.split("");
        var length = textArray.length - 1;
        var i = 0;

        $("#div").append('<p class="text' + n + '"></p>' + "\n"); // creates a paragraph to print every character to (n is a global var)

        intv = setInterval(function() {
            if(i <= length) {
                var a = textArray[i];
                $('#div .text' + n).text($('#div .text' + n).text() + a); // appends the character to the paragraph created above
                i++;
            }
            else {
                alert("stopping interval..."); // just lets me know when the interval is stopping
                clearInterval(intv);
                intv = null;
                n++;
            }
        }, 60);
    }
    else {
        alert("the interval is not null"); // lets me know if the previous setInterval has stopped firing
    }
}

以下是我的称呼方式:

type("string one");
type("string two");

问题是“字符串一”和“字符串二”都同时触发,并且无论是开始无限循环还是只有第一个起作用。

我真的不知道是否有办法解决这个问题,我的搜索没有任何结果。我不知道这是否是一个常见问题。有没有办法可以保持第二个字符串不被触发直到第一个字符串完成?

提前致谢。

2 个答案:

答案 0 :(得分:3)

setInterval实际上只计划每隔很多毫秒运行一个间隔。在那之后,一切仍然有效,所以你可以使用页面上的其他模块(如果你不能,那将是没用的。)

如果您确实要等到间隔#1完成,您可以调用您传递的功能。类似的东西:

function type(text, functionIfDone) {
// ...
            clearInterval(intv);
            functionIfDone();  // call the function now because the interval is over

使用它像:

type("string one", function() {
    type("string two");
});

如果您不想使用回调,那么您可以使用一些负责排队的辅助函数:http://jsfiddle.net/pZtje/

var currentInterval;
var intervals = [];

var startInterval = function(func, time) {
    intervals.push({
        func: func,
        time: time
    });
    checkQueue();
};

var checkQueue = function() {
    if(currentInterval == null) {
        var item = intervals.shift();
        if(item) {
            currentInterval = setInterval(item.func, item.time);
        }
    }
};

var stopInterval = function() {
    clearInterval(currentInterval);
    currentInterval = null;
    checkQueue();
};


// Usage:

var i = 0;
function foo() {
    console.log(i);
    i++;
    if(i === 3) {
        i = 0;
        stopInterval();
    }
}

startInterval(foo, 1000);
startInterval(foo, 1000);

答案 1 :(得分:2)

看看这里:http://jsfiddle.net/ymxu5/12/

首先,设置一个能跟踪我们所在位置的功能队列:

function Queue(){
    this._fns = [];
    this._args = [];
    this._running = false;
    var that = this;

    this.add = function(fn){
        console.log(fn.name + " added");
        that._fns.push(fn);
        var args = Array.prototype.slice.call(arguments, 1);
        that._args.push(args);

        if (!that._running)
            that.next();

        return that;
    },
    this.next = function(){        
        if (that._fns.length == 0){
            that._running = false;
        }
        else{
            that._running = true;
            that._fns.shift().apply(that, that._args.shift());
        }
    }
};

然后,您需要调整方法以使用queue.next();。我已设置Queue对象来调用每个函数,将this的上下文更改为Queue对象,这就是使用var queue = this;的原因。

function type(text){
    var queue = this;
    var $con = $("<p>").appendTo("#div");

    var typeText = function(con, txt, cursor){
        if (cursor < txt.length){
            con.text(con.text() + txt[cursor]);
            setTimeout(function(){
                typeText(con, txt, cursor + 1);
            }, 60);
        }
        else{
            setTimeout(function(){
                queue.next();
            }, 250);
        }
    };
    typeText($con, text.split(""), 0);
}

function flicker(sel){
    var queue = this;

    // note that this will cause issues if "sel" selects multiple things
    // because it will create multiple callbacks with jQuery, and `next` will
    // be called once for each item in "sel"
    $(sel).fadeOut("fast", function(){
        $(this).fadeIn("fast", function(){
            queue.next();
        });
    });
}

您希望在整个范围内都可以访问Queue个对象。我在这里做到了全球:

var q = new Queue();
var senNum = 0;

$(function(){    
    $("#button").click(function(){
        q.add(type, "Sentence " + (++senNum)).add(flicker, "p:nth-child("+senNum+")");
    });        
});

我也冒昧地使add方法可链接,所以你可以像上面一样使用它。

这是使用一些方法创建类似控制台的界面的示例:

http://jsfiddle.net/ymxu5/15/