开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
今天遇到一道面试题
刚开始我考虑的是setTimeout 去实现循环 后面发现 实现绿灯闪的时候 比较麻烦 动画还是考虑requestAnimationFrame去替代setTimeout ,性能优化的标准 使用requestAnimationFrame 的话 就要用递归 ,时间就需要时间戳去判断了
let div = document.createElement('div')
div.id = 'channelLight'
div.style="width:100px;height:100px;background:red"
document.body.append(div)
let color = ['red','green','yellow']
let index = 1,timer,bingTimer
let time = new Date()
let delay = 20000,twinkleTime = 5000
//传入循环的时间参数 用递归的方式去判断
function setTime(delay,index){
index >= color.length-1 ? 0 : index
timer = requestAnimationFrame(()=>{
let newTime = new Date()
if(newTime-time >= delay){
render(index)
}else{
setTime(delay,index)
}
})
}
//渲染
function render(index){
let div = document.getElementById('channelLight')
div.style.background = `${color[index]}`
time = new Date()
if(index == 1 ){
twinkle()
}
let i = index +1 > color.length -1 ? 0 :index+1
setTime(delay,i)
}
//处理闪一闪的函数
function twinkle(){
requestAnimationFrame(()=>{
let dateTime = new Date()
if(dateTime - time >= (delay-twinkleTime)){
//闪一闪
renderTwinkle(twinkleTime)
}else{
twinkle()
}
})
}
// 闪的时候的渲染 里面要处理递归
function renderTwinkle(t){
let time = new Date()
show()
let timeout = null
function show(){
requestAnimationFrame(()=>{
if(new Date()- time <= t){
div.style.background = `#fff`
requestAnimationFrame(()=>{
div.style.background = `${color[index]}`
timeout && clearTimeout(timeout)
timeout = setTimeout(show,twinkleTime/10 < 20 ? 20 : twinkleTime/10)
})
}else{
timeout && clearTimeout(timeout)
}
})
}
}
setTime(delay,index)