setTimeout and difference in Time
I have a loop kind of like this
var lastUpdateTime = (new Date()).getTime(),
diffTime = 0,
i = 0;
function update() {
var updateTime = 1000 / 60,
now;
// do some stuff...
console.log("update");
console.log(" - i:" + i);
now = (new Date()).getTime();
diffTime = now - lastUpdateTime;
lastUpdateTime = now;
console.log(" - - before diffTime:" + diffTIme);
while (diffTime >= updateTime) {
diffTime -= updateTime;
}
console.log(" - - after diffTime:" + diffTime);
updateTime -= diffTime;
console.log(" - - updateTime:" + updateTime);
if ( i < 10) {
i += 1;
setTimeout(update, updateTime);
}
}
When setTimeout is called, the time that has passed during the updateTime does not seem to of passed when diffTime is updated. Here, I have set it to be 1000 / 60
milliseconds, but I get numbers there are less than that, which doesn't make sense. It should be more than or equal to. Why is it doing that?
In response to davin:
I don't use setInterval
because it stacks the calls http://bonsaiden.github.com/JavaScript-Garden/#other.timeouts.
The while
reduces the diffTime into 1000 / 60
blocks of time, especially when it is greater than 16 ms. Modulus operator is expensive.
The reason I know that the updateTime
hasn't passed is that print out the diffTime
before I manipulate it. The number always comes out less than updateTime
given to setTimeout
.
Log:
update
- i:0
- - before diffTime:1
- - after diffTime:1
- - updateTime:15.666666666666668
update
- i:1
- - before diffTime:12
- - after diffTime:12
- - updateTime:4.666666666666668
update
- i:2
- - before diffTime:54
- - after diffTime:3.999999999999993
- - updateTime:12.666666666666675
update
- i:3
- - before diffTime:13
- - after diffTime:13
- - updateTime:3.666666666666668
update
- i:4
- - before diffTime:11
- - after diffTime:11
- - updateTime:5.666666666666668
update
- i:5
- - before diffTime:14
- - after diffTime:14
- - updateTime:2.666666666666668
Looking at the updateTime
and the before diffTime
, the timing doesn't make sense. For example I have 15.666666666666668
, but the difference in time after it is 12
.
New Log:
updateWithoutTimer
- i:0
- - before diffTime:2
- - after diffTime:2
- - updateTime:14.666666666666668
updateWithoutTimer
- i:1
- - before diffTime:5
- - after diffTime:5
- - updateTime:11.666666666666668
updateWithoutTimer
- i:2
- - before diffTime:8
- - after diffTime:8
- - updateTime:8.666666666666668
updateWithoutTimer
- i:3
- - before diffTime:86
- - after diffTime:2.66666666666665
- - updateTime:14.000000000000018
updateWithoutTimer
- i:4
- - before diffTime:24
- - after diffTime:7.333333333333332
- - updateTime:9.333333333333336
updateWithoutTimer
- i:5
- - before diffTime:34
- - after diffTime:0.6666666666666643
- - updateTime:16.000000000000004
updateWithoutTimer
- i:6
- - before diffTime:24
- - after diffTime:7.333333333333332
- - updateTime:9.333333333333336
updateW开发者_JAVA百科ithoutTimer
- i:7
- - before diffTime:27
- - after diffTime:10.333333333333332
- - updateTime:6.333333333333336
updateWithoutTimer
- i:8
- - before diffTime:14
- - after diffTime:14
- - updateTime:2.666666666666668
updateWithoutTimer
- i:9
- - before diffTime:2
- - after diffTime:2
- - updateTime:14.666666666666668
updateWithoutTimer
- i:10
- - before diffTime:2
- - after diffTime:2
- - updateTime:14.666666666666668
Here is another log that does not do it only on the first tick. When I have tested it, it seems to work like setTimeout(func)
, so no millisecond elapse. The delay seems to be the browser. Currently I am using Mozilla Aurora 6.0a and Google Chrome 14.0.803 dev.
I thought I would just recheck both browsers and I go the same result in Aurora, but Chrome worked as expected. Oddly I tested it before hand and it didn't work correctly. I assume it is a bug in Aurora. I have submitted a bug report to mozilla.
I assign lastTimeUpdate because I want to find out how long it has taken to get to this frame and how long the frame has taken, so I can process it accordingly.
Update:
Here is the bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=668765. Apparently, setTimeout
will try to do the right thing. If it has recently fired late it will try to fire early.
Your code doesn't make much sense to me. What is that while
loop doing? Why not just have a modulus operator after rounding and do it in 1 step? Why are you subtracting this difference in such a strange manner? On what basis do you claim that the time hasn't passed? I see no checking of any value.
Of course you're getting values that are <= updateTime = 1000/60 ~ 16
, because you set the interval to be such: You loop until diffTime < updateTime
and then execute the new timer for a delay of updateTime - diffTime
. The maths is simple: 0 < updateTime - diffTime < updateTime
.
It looks like you want to update every so often. That's why they invented setInterval
. You're reinventing the wheel which is both unnecessary and less reliable than the browser's implementation.
UPDATE
I presume you're not an assembly programmer. The modulus operator will perform a constant number of arithmetic operations, say 4 worst-case. Your loop will perform almost the same number of operations each iteration, since it has to perform the condition check, the subtraction, the assignment and a branch (which can itself be expensive). So if your loop does even 2 iterations its already more expensive than a modulus operator.
Regarding your times, you say that it happens "all the time" although from that output it looks like it happens only the first time. I ran the same code and the numbers made sense. What platform are you running on? Does this ever happen other than on the first tick? Does it happen every time on the first tick? Some more information would be helpful.
As an aside, you're overestimating your diffTime
because you're setting lastUpdateTime
before you do a whole bunch of things. What you should be doing is assigning lastUpdateTime
at the point of setTimeout
.
精彩评论