Javascript setTimeout 意外输出

标签 javascript timer settimeout

我一直在使用脚本在我的应用程序中使用 setInterval(fn,delay) 函数,在阅读了 setTimeout 和 JS 的工作原理后,我遇到了一些奇怪的结果,所以我做了一个测试: 这是 jsfiddle https://jsfiddle.net/jyq46uu1/2/

和建议的代码:

var limit        = 1000000000;
var intervals    = 0;
var totalTime    = new Date();
var startTime    = new Date();

var uid = setInterval(
    function () {
        // final lap?
        if (intervals == 9) clearInterval(uid);

        for (i = 0; i < limit; i += 1) {
            // just working the CPU
        }
        // reduce the iterations
        limit = limit / 10;   
        intervals += 1;        

        console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime));
        // reset the time
        startTime    = new Date();
    }, 250, 9);

好的,根据我从 http://ejohn.org/blog/how-javascript-timers-work/ 得到的红色信息即使“线程被阻塞”,Javascript 也会对 setInterval 中的函数进行计时器调用,因此如果函数仍在执行,则调用只是排队等等......在我的笔记本中,代码产生了这个:

"Interval 1 Time elapsed    : 4264" 
"Interval 2 Time elapsed    : 477" 
"Interval 3 Time elapsed    : 91" 
"Interval 4 Time elapsed    : 170" 
"Interval 5 Time elapsed    : 246" 
"Interval 6 Time elapsed    : 242" 
"Interval 7 Time elapsed    : 248" 
"Interval 8 Time elapsed    : 248" 
"Interval 9 Time elapsed    : 248"

好吧,如果我的红色是真的,到第一个间隔结束时,所有函数调用都在队列中......在我的脚本中,我减少了每次执行的工作,所以每次调用应该花费更少秒比前一个,但无论我设置多少次迭代,耗时总是在第 4 次运行后采用间隔速度。 也许我弄错了,但是如果到 4264 时所有函数都已经在队列中并且应该立即运行,它们应该显示更少的时间,对吗? ...如果第 3 次迭代显示 91 而其他人紧随其后,他们应该采用 91 或更少。但事实并非如此。

如果你明白发生了什么,请向我解释一下,因为我想我遗漏了什么。

最佳答案

我认为第一次不是从队列中的初始间隔开始计算,而是从你设置startTime的那一点开始。

然后第一个计时器计算初始化时间、环境创建、变量和计时器分配。

试试这个修改:

var limit        = 1000000000;
var intervals    = 0;
var totalTime    = new Date();
var startTime    = false;

var uid = setInterval(
    function () {
        if (!startTime) startTime = new Date();
        // final lap?
        if (intervals == 9) clearInterval(uid);

        for (i = 0; i < limit; i += 1) {
            // just working the CPU
        }
        // reduce the iterations
        limit = limit / 10;   
        intervals += 1;        

        console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime));
        // reset the time
        startTime    = new Date();
    }, 250, 9);

此外,第一次花费的时间可能更长,可能是因为函数正在被解释,随后的时间被 Javascript JIT 执行“编译”/优化(参见 https://en.wikipedia.org/wiki/Just-in-time_compilation)。查看此代码以查看证明

var limit        = 1000000000;
var intervals    = 0;
var totalTime    = new Date();
var startTime    = new Date();

var uid = setInterval(
    function () {
        startTime = new Date();
        // final lap?
        if (intervals == 9) clearInterval(uid);

        for (i = 0; i < limit; i += 1) {
            // just working the CPU
        }
        // reduce the iterations
        limit = limit / 10;   
        intervals += 1;        

        console.log('Interval ' + intervals +' Time elapsed : ' + (new Date() - startTime));
        // reset the time
        startTime    = new Date();
    }, 250, 9);

输出:

Interval 1 Time elapsed : 3249
Interval 2 Time elapsed : 299
Interval 3 Time elapsed : 31
Interval 4 Time elapsed : 5
Interval 5 Time elapsed : 0
Interval 6 Time elapsed : 0
Interval 7 Time elapsed : 0
Interval 8 Time elapsed : 0
Interval 9 Time elapsed : 0
Interval 10 Time elapsed : 0

setInterval 不能很好地衡量下一次执行应该排队的时间。我认为这与 sleep()ing 有关。如果进程正在占用 CPU 并将其挂起(就像您所做的那样),这是不可靠的。

setInterval 只保证这一点:

  • 第 1 次执行不会在 250 毫秒内发生。
  • 第 2 次执行不会在提前 2*250 毫秒内发生。
  • 第 3 次执行不会在提前 3*250 毫秒内发生。
  • ...

setInterval 不保证某些执行会在未来确定的时间之前发生。这取决于当前的 CPU 使用率。

排队函数的排队和启动也取决于当前的 CPU 使用率。

特别常见的建议 如果您需要定期执行一个函数,我推荐这种方法,它可以保证两次执行之间的延迟始终大于 250 毫秒

var t = false;
var fun = function() {
    console.log("run");
    t = setTimeout(fun, 250);
}
fun();

关于Javascript setTimeout 意外输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31283678/

相关文章:

javascript - D3 饼图弧线过渡到 180° 时不可见

javascript - 到达对象的属性

java - 如何启动不同的定时器

jquery 在输入更改时扩展 setTimeout 函数

javascript - 使用 settimeout 绕过地理编码查询限制

javascript - Jest 在 react-native 中遇到了意外的标记

javascript - 在js文件中调用Express.js的函数

javascript - 固定导航栏顶部的自动完成列表

c# - C#: Call a method every 5 minutes from a foreach loop

javascript - 为什么这个延迟的 WHILE 循环会导致大量内存泄漏?