SetInterval quasi?
You can only ensure that the callback function does not run before the specified event interval, but may run at that time or after, depending on the state of the event queue. JavaScript you Don’t Know p143
Use setTimeout instead of setInterval
- Why substitute?
SetInterval will wait for the call stack to be empty before executing the callback. If the previous code has been executed for too long, beyond the interval set for setInterval, the callback function will be queued. When the stack is finally empty, the callback function in the queue will be executed immediately. SetInterval in the Web APIs has been timing the callback function for a while, and will soon queue the callback function again. In addition, if setInterval itself gives a callback that takes longer than the setInterval, it will also cause this problem, losing the value of setting the interval.
- How to replace?
Train of thought
You can refer to this video, the idea is very detailed, JavaScript using setTimeout simulation to implement setInterval, but the video does not say how to clear the timer, the following record the thought process of implementing the clear timer.
Use: timer = mySetInterval(fn, delay) Clear: myClearInterval(timer)
// Method 1 (this is not good to clear the timer, because it is not good to set the global timer, the video does not talk about this method)
function mySetInterval(fn, delay) {
setTimeout(() = > {
console.log(new Date().toLocaleString()) // You can print the time to see
fn()
mySetInterval(fn, delay)
}, delay)
}
/ / test
function testmySetInterval() {
console.log('testmySetInterval')
}
mySetInterval(testmySetInterval, 1000)
Copy the code
Method one is not good to clear the timer, because mySetInterval must return a timer to clear it, right? Let’s do method two.
// Method 2 (video method, no write how to clear timer)
function mySetInterval(fn, delay) {
function inside() {
console.log(new Date().toLocaleString()) // You can print the time to see
fn()
setTimeout(inside, delay)
}
setTimeout(inside, delay)
}
// Start thinking:
MySetInterval (fn, delay) returns a timer (fn, delay).
function mySetInterval(fn, delay) {
let timer = null
function inside() {
clearTimeout(timer)
fn()
timer = setTimeout(inside, delay)
}
timer = setTimeout(inside, delay)
return timer // Timer = mySetInterval(fn, delay
}
// mySetInterval is called only once, which always returns the first setTimeout timer. How do I make the timer unfixed? Object! Return an object clearTimeout() as the property value! The property value is a method that clears the timer, which myClearInterval calls! Write like this:
function mySetInterval(fn, delay) {
let timer = null
function inside() {
console.log(new Date().toLocaleString()) // Print to see the time
clearTimeout(timer) // Remove the previous timer, using the closure, inside access to variables outside its scope, that is, the timer under mySetInterval
fn()
timer = setTimeout(inside, delay)
}
timer = setTimeout(inside, delay)
return { // Return an object clearTimeout() as the property value!
clear() {
clearTimeout(timer)
}
}
}
// Clear the timer
function myClearInterval(flagTimer) {
flagTimer.clear()
}
/ / test
function testmySetInterval() {
console.log('testmySetInterval')}const timer = mySetInterval(testmySetInterval, 1000)
// Call myClearInterval(timer)
Copy the code
encapsulation
function mySetInterval(fn, delay) {
let timer = null
function inside() {
console.log(new Date().toLocaleString()) // Print to see the time
clearTimeout(timer)
fn()
timer = setTimeout(inside, delay)
}
timer = setTimeout(inside, delay)
return {
clear() {
clearTimeout(timer)
}
}
}
// Clear the timer
function myClearInterval(flagTimer) {
flagTimer.clear()
}
/ / test
function testmySetInterval() {
console.log('testmySetInterval')}const timer = mySetInterval(testmySetInterval, 1000)
// Call myClearInterval(timer)
Copy the code
RequestAnimationFrame replaces the timer
const RAF = {
intervalTimer: null.timeoutTimer: null.setTimeout(cb, interval) { // Implement setTimeout
let now = Date.now
let stime = now()
let etime = stime
let loop = () = > {
this.timeoutTimer = requestAnimationFrame(loop)
etime = now()
if (etime - stime >= interval) {
cb()
cancelAnimationFrame(this.timeoutTimer)
}
}
this.timeoutTimer = requestAnimationFrame(loop)
return this.timeoutTimer
},
clearTimeout() {
cancelAnimationFrame(this.timeoutTimer)
},
setInterval(cb, interval) { // Implement setInterval
let now = Date.now
let stime = now()
let etime = stime
let loop = () = > {
this.intervalTimer = requestAnimationFrame(loop)
etime = now()
if (etime - stime >= interval) {
stime = now()
etime = stime
cb()
}
}
this.intervalTimer = requestAnimationFrame(loop)
return this.intervalTimer
},
clearInterval() {
cancelAnimationFrame(this.intervalTimer)
}
}
let count = 0
function a() {
console.log(count)
count++
}
RAF.setTimeout(a, 1000)
Copy the code