简体   繁体   English

setInterval(javaScript):有没有已知的错误?

[英]setInterval (javaScript): are there known bugs?

99 times out of 100, this works perfectly: 100次中99次,这完美地运作:

function a(){
   setInterval("b()",1000); 
   updateText("still working");
}
function b(){
   timer++;
   updateText(timer);
}

Occasionally the first loop waits for 20 seconds to 2 minutes. 偶尔第一个循环等待20秒到2分钟。 Thereafter it runs perfectly. 此后它完美运行。 I know the timer can pause on Android phones (when the soft keyboard is shown). 我知道计时器可以在Android手机上暂停(当显示软键盘时)。 Are there other conditions that might delay setInterval? 还有其他条件可能延迟setInterval吗?

Firstly, it is strongly advised you provide a callback( function ) as the first argument and not a string, because that string is evaluated in the global scope and we all know that bad things happen when we use eval in js (related eval post : When is JavaScript's eval() not evil? ). 首先,强烈建议你提供一个回调( function )作为第一个参数而不是字符串,因为该字符串是在全局范围内计算的,我们都知道当我们在js中使用eval时会发生不好的事情(相关的eval post: 什么时候JavaScript的eval()不是邪恶的? )。
So, your 所以,你的

setInterval("b()", 1000); 

should be rewritten as : 应改写为:

setInterval(b, 1000); 

or: 要么:

setInterval(function() { b(); }, 1000); 

I also recommend you use setTimeout to simulate a setInterval . 我还建议您使用setTimeout来模拟setInterval

The main downfall of the setInterval function is that it executes a block of code every n milliseconds, regardless of the execution of the previous block of code. setInterval函数的主要缺点是它每n毫秒执行一段代码,而不管前一代码块的执行情况如何。
So if for some reason a setInterval callback takes longer to execute than the delay provided, it will cause some stack overflows . 因此,如果由于某种原因, setInterval回调的执行时间比提供的延迟要长,则会导致一些堆栈溢出

Let's take the following code for example : 我们以下面的代码为例:

function foo() {
    // this takes about 2 seconds to execute
    // .. code here
}
setInterval(foo, 1000);

This will actually freeze the browser because it will execute foo for an (almost) infinite number of times but it will never finish it. 这实际上将冻结浏览器,因为它将执行foo (几乎)无限次,但它永远不会完成它。

The solution in this kind of case is to emulate the setInterval with setTimeout , in order to ensure that the callback has finished to execute before calling it again: 在这种情况下的解决方案是使用setTimeout模拟setInterval ,以确保在再次调用之前回调已完成执行:

function foo() {
    // this takes about 2 seconds to execute
    // .. code here
}
function newSetInterval(callback, duration, callbackArguments) {
    callback.apply(this, callbackArguments);
    var args = arguments,
        scope = this;

    setTimeout(function() {
        newSetInterval.apply(scope, args);
    }, duration);
}
newSetInterval(foo, 1000);

Now, foo is called again only after the previous instance has finished the code execution. 现在,只有在前一个实例完成代码执行后才会再次调用foo

I would apply the same thing to your code, in order to let the browser decide when it can execute the code, and not to force it to execute the block of code weather it's busy at that moment or not: 我会对你的代码应用相同的东西,以便让浏览器决定何时可以执行代码,而不是强迫它执行代码块,因为它在那个时刻是忙碌的:

function a() {
   newSetInterval(b, 1000); 
   updateText("still working");
}
function b() {
   timer++;
   updateText(timer);
}
function newSetInterval(callback, duration, callbackArguments) {
    callback.apply(this, callbackArguments);
    var args = arguments,
        scope=this;

    setTimeout(function() {
        newSetInterval.apply(scope, args);
    }, duration);
}

If you're interested, I've rewritten the setInterval and clearInterval functions in order to use them anywhere, without taking care of stack overflows : 如果您感兴趣,我已经重写了setIntervalclearInterval函数,以便在任何地方使用它们,而不需要处理堆栈溢出:

function setInterval(f, time) {
    setInterval.ids = setInterval.ids || {};
    setInterval.idCount = setInterval.idCount || 0;
    var that = this,
        id = setInterval.idCount++,
        // to prevent firefox bug that adds an extra element to the arguments
        l = arguments.length - 2;

    (function theFn() {
        // to prevent firefox bug that adds an extra element to the arguments
        var args = [].slice.call(arguments, 0, l);
        f.apply(this, args);
        setInterval.ids[id] = setTimeout.apply(this, [theFn, time].concat(args));
    }).apply(that, [].slice.call(arguments, 2, arguments.length));
    return id;
}


function clearInterval(id) {
    if(!setInterval.ids || !setInterval.ids[id]) {
        return false;
    }
    clearTimeout(setInterval.ids[id]);
    return true;
} 

try this, 尝试这个,

setInterval(b, 1000);

or 要么

setInterval(function(){
   timer++;
   updateText(timer);
}, 1000);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM