首先 了解下 setTimeout的浅层原理,setTimeout 是通过浏览器异步api执行,执行完成之后,回调交给宏任务,假设宏任务队列已经有其他任务,就会导致 setTimeout 回调执行延后,从而不精准。
浏览器1s执行60帧,大概两帧之间的执行时间差为16ms,认为这样是比较好的体验。
requestAnimationFrame 是不需要设定时间,大概16ms执行一次。所以使用requestAnimationFrame 会更准确
<!--使用requestAnimationFrame 实现setInterval -->
export function mySetInterval(cb, cancelCb) {
let timer = null;
let pre = new Date()
let fn = function() {
timer = requestAnimationFrame(() => {
let cur = new Date()
if (cur - pre >= 1000) {
cb()
pre = cur
}
timer = requestAnimationFrame(fn)
if (cancelCb && cancelCb()) {
timer && cancelAnimationFrame(timer)
}
})
}
fn()
}
<!-- 倒计时 -->
export default class Countdown {
constructor({ endTime }) {
this.endTimetamp = new Date(endTime).getTime()
console.log(endTime, this.endTimetamp);
this.countDownDate = {}
mySetInterval(this.countDown.bind(this), this.cancel.bind(this))
}
countDown() {
let dis = (this.endTimetamp - new Date().getTime()) / 1000
this.countDownDate = this.calculator(dis)
console.log('发送事件---->', this.countDownDate);
// this.on('countdown', this.countDownDate)
}
cancel() {
return this.countDownDate && this.countDownDate.timetamp <= 0 ? true : false
}
calculator(second) {
let sec = 1,
min = 60 * sec,
hour = 60 * min,
day = 24 * hour;
return {
day: parseInt(second / day),
hour: parseInt(second % day / hour),
min: parseInt(second % hour / min),
second: parseInt(second % min),
timetamp: second
}
}
}
export default Countdown
new Countdown({
endTime: '2021-11-30 12:00'
})
优点:
先来回答一下下面这个问题:对于 setTimeout(function() { console.log(timeout) }, 1000) 这一行代码,你从哪里可以找到 setTimeout 的源代码(同样的问题还会是你从哪里可以看到 setInterval 的源代码)?
由于 Web Worker 本质上是Web线程,因此你可以在其中无限循环而不阻塞主线程。这使你可以访问微秒级的时间分辨率。这对于在 Worker 中做出时间关键的决策是特别实用的,可以让主线程准确的知道什么时候合适
在JavaScript中,我们经常使用requestAnimationFrame、setTimeout、setInterval和setImmediate来控制代码的执行时机。它们各有特点和适用场景:requestAnimationFrame: requestAnimationFrame主要用于浏览器动画渲染。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!