Javascript setTimeout意外输出

Gab*_*ich 7 javascript timer settimeout

我一直在使用在我的应用程序中使用setInterval(fn,delay)函数的脚本,在阅读了setTimeout和JS如何工作后,我遇到了一些奇怪的结果,所以我做了一个测试:这是jsfiddle https:// jsfiddle.净/ 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);
Run Code Online (Sandbox Code Playgroud)

好吧,从我的红色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"
Run Code Online (Sandbox Code Playgroud)

好吧,如果我的红色是真的,到第一个间隔完成时,所有函数调用都在队列中...在我的脚本中我减少了每次执行的工作,所以每个调用应该花费的时间少于前一个,但无论我设置多少迭代,经过的时间总是在第四次运行后获得间隔速度.也许我弄错了但是如果到4264时所有功能都已经在队列中并且假设立即运行,那么它们应该显示更少的时间,对吧?...如果第3次迭代显示91而其他人只是落后,则应该取91或更少.但这种情况并非如此.

如果你了解发生了什么,请向我解释,因为我觉得我错过了什么.

jpe*_*lli 1

我认为第一次不是从队列中的初始间隔开始计算,而是从您设置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);
Run Code Online (Sandbox Code Playgroud)

另外,第一次需要更长的时间,可能是因为函数正在被解释,然后后续时间由 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);
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

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

setInterval 仅保证这一点:

  • 执行 1 不会在 250 毫秒内发生。
  • 第 2 次执行不会在接下来的 2*250ms 内发生。
  • 第 3 次执行不会在 3*250ms 内发生。
  • ...

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

排队和启动排队函数还取决于当前的 CPU 使用情况。

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

var t = false;
var fun = function() {
    console.log("run");
    t = setTimeout(fun, 250);
}
fun();
Run Code Online (Sandbox Code Playgroud)