重新认识定时器

270 阅读2分钟

这几天重拾了一个以前遇到的面试题,联想起以前遇到的 “为什么 js的setTimeout 跟 css的transition 的时间对不上的问题”,又有了一些新的发现 。

友情提示:阅读本文需要了解 Macrotasks、Microtasks、Event Loop、执行栈。

传送门:zhuanlan.zhihu.com/p/33058983

定时器

定时器有两种,分别是 setInterval 和 setTimeout 。区别在于 setTimeout 只执行一次,而 setInterval 会一直循环执行。这里不详细讨论区别,只聊聊定时器的执行顺序。

DEMO 1

setTimeout(()=>{ console.log("1") }, 3000);
console.log("2")

// => 2
// => 1

定时器回调函数的执行时间

上面的🌰,会在控制台先输出 2,然后在3秒之后会执行 setTimeout 的匿名回调函数,再输出 1

setTimeout 是一个宏任务,它的回调函数会在执行栈中的所有任务执行完毕之后执行。

那么 setTimeout 是在何时开始计时的呢?

DEMO 2

console.log("1", Date.now())

setTimeout(() => { console.log("2", Date.now()) }, 3000);

let time = Date.now();
let now = Date.now();
while (now - time <= 3000) { now = Date.now(); }

console.log("3", Date.now())

setTimeout(() => { console.log("4", Date.now()) }, 2000);

time = Date.now();
now = Date.now();
while (now - time <= 2000) { now = Date.now(); }

console.log("5", Date.now())

// => 1 1602514139821 
// => 3 1602514142823
// => 5 1602514144824
// => 2 1602514144824
// => 4 1602514144824 

通过输出顺序可以看出,在执行到 setTimeout 的时候已经开始倒计时,由于 while 的耗时操作,导致输出 5 1602514144824 之后马上执行了两个定时器里面的回调函数。

在其他文章中有看到 定时器线程 这种说法,但是并没有找到具体的资料证实,不传瑶不信瑶

结论

transition: 由css定义,浏览器主动触发,在另一个独立线程里面执行。

setTimeout:在js的执行线程里,会受到线程里面的耗时操作导致延迟执行。