Javascript setTimeout 意外输出
Javascript setTimeout unexpected output
我一直在使用脚本在我的应用程序中使用 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 中得到的红色,即使 "thread is blocked" 也让定时器调用 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 或更少。但事实并非如此。
如果你明白发生了什么,请向我解释一下,因为我想我遗漏了什么。
我不确定我在这方面是否正确,这是我所知道的 "Javascript"。
Javascript是基于事件的触发,还有"no queue and wait"。它将同时进行(类似于线程)。
我想这会很有意义,因为它解释和处理下一个的速度有多快。
我认为第一次不是从队列中的初始间隔开始计算,而是从您设置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 执行后续时间 "compiled"/优化(参见 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 使用情况。
额外的常见建议
如果你需要周期性地执行一个函数,我推荐这种方法来保证每次执行之间的延迟总是大于 250ms
var t = false;
var fun = function() {
console.log("run");
t = setTimeout(fun, 250);
}
fun();
那我有几点要说,先看结果吧
"new"代码:
var limit = 1000000000;
var intervals = 0;
var totalTime = new Date();
top.uid = setInterval(
function () {
startTime = new Date();
// final lap?
if (intervals == 9) clearInterval(top.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
}, 1);
请注意,我从第 4 行删除了变量 startTime 并将其传递到函数的开头,因此,计算的时间对于所有调用都是相同的。
我将 TIMER 表格从 250ms 更改为 1ms,因此您不必从每个结果中计算 -250ms。
新结果非常一致,表明现在花在计算上的时间非常可接受且连贯。
希望我帮助清理它。
我一直在使用脚本在我的应用程序中使用 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 中得到的红色,即使 "thread is blocked" 也让定时器调用 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 或更少。但事实并非如此。
如果你明白发生了什么,请向我解释一下,因为我想我遗漏了什么。
我不确定我在这方面是否正确,这是我所知道的 "Javascript"。
Javascript是基于事件的触发,还有"no queue and wait"。它将同时进行(类似于线程)。
我想这会很有意义,因为它解释和处理下一个的速度有多快。
我认为第一次不是从队列中的初始间隔开始计算,而是从您设置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 执行后续时间 "compiled"/优化(参见 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 使用情况。
额外的常见建议 如果你需要周期性地执行一个函数,我推荐这种方法来保证每次执行之间的延迟总是大于 250ms
var t = false;
var fun = function() {
console.log("run");
t = setTimeout(fun, 250);
}
fun();
那我有几点要说,先看结果吧
"new"代码:
var limit = 1000000000;
var intervals = 0;
var totalTime = new Date();
top.uid = setInterval(
function () {
startTime = new Date();
// final lap?
if (intervals == 9) clearInterval(top.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
}, 1);
请注意,我从第 4 行删除了变量 startTime 并将其传递到函数的开头,因此,计算的时间对于所有调用都是相同的。 我将 TIMER 表格从 250ms 更改为 1ms,因此您不必从每个结果中计算 -250ms。
新结果非常一致,表明现在花在计算上的时间非常可接受且连贯。
希望我帮助清理它。