实现红绿灯

118 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

今天遇到一道面试题

image.png

刚开始我考虑的是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)