setTimeout与setInterval计时

1.setTimeout

setTimeout(fn, 10);

当代码执行到此行时,开始计时,并在10ms之后,把fn加入任务队列.
原因:
如果先把fn加入任务队列,再等10ms之后触发会有问题:因为每次同步任务栈被清空之后,都要读取任务队列的第一个任务立即执行,所以没有10ms的等待触发时间,所以必须是等待触发时机再加入任务队列。
下面拿代码验证下:

setTimeout(function () {console.log('a')}, 10); // line 1
setTimeout(function () {console.log('b')}, 0); // line 2
var sum = 0; // line 3
for (var i = 0; i < 10000000; i ++) { // line 4
    sum += i; // line 5
} // line 6
console.log(sum); // line 7
setTimeout(function () {console.log('c');}, 0); // line 8

析:
执行到line1时,定时异步操作:10ms之后加入任务队列,开始计时并继续往下执行。
执行到line2时:定时异步操作:立即加入任务队列
执行到line3、4、5、6、7时,同步任务,耗时10ms,line1的回调加入任务队列
执行到line8时,立即加入任务队列
此时同步代码按顺序执行结束,开始执行异步任务,任务队列的顺序是:b、a、c
所以结果应该是:b、a、c
浏览器执行,结果确实是b、a、c
下面对代码进行一些修改:

setTimeout(function () {console.log('a')}, 10); // line 1
setTimeout(function () {console.log('b')}, 0); // line 2
var sum = 0; // line 3
for (var i = 0; i < 10; i ++) { // line 4
    sum += i; // line 5
} // line 6
console.log(sum); // line 7
setTimeout(function () {console.log('c');}, 0); // line 8

析:
执行到line1时,定时异步操作:10ms之后加入任务队列,开始计时并继续往下执行。
执行到line2时:定时异步操作:立即加入任务队列
执行到line3、4、5、6、7时,同步任务,耗时小于10ms
执行到line8时,立即加入任务队列
此时同步代码按顺序执行结束,开始执行异步任务,任务队列的顺序是:b、c
然后计时10ms结束,line1的回调加入任务队列
所以结果应该是:b、c、a
浏览器执行,结果确实是b、c、a
2.setInterval
setInterval:

setInterval(fn, 10);

每隔10msfn加入任务队列或者立即被执行。
下面看一段代码:

var interval = setInterval(function () {
    var date = new Date();
    console.log(date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
}, 10);
var sum = 0;
for (var i = 0; i < 1000000; i ++) {
    sum += i;
}
// 清除定时器,避免卡死浏览器
setTimeout(function () {
    clearInterval(interval);
}, 100);

执行结果如下:05
析:
前两次的执行时间差7ms,原因是第一次定时任务触发的时候,同步任务为执行完成,所以进入任务队列等候,
所以第二次与第一次执行时间差小于10ms

参考文章:
JavaScript异步机制

此条目发表在JavaScript分类目录。将固定链接加入收藏夹。

发表评论

邮箱地址不会被公开。 必填项已用*标注