js红绿灯的三种实现方法

2,693 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

突然想起来之前我面试时候的一道面试题,用js实现一个红绿灯,想想当时发挥的不如人意,今天就来回顾复习一下。

题目

某个路口的红绿灯,会按照红灯亮5s,黄灯亮2s,绿灯亮3s这样的顺序无限循环。要求:每一秒打印当前在亮的灯。

// 打印结果形如(每秒打印一次)
红灯
红灯
红灯
红灯
红灯
黄灯
黄灯
绿灯
绿灯
绿灯
...

解题方法

方法1——定时器递归

思路

封装一个函数专门打印入参内容,入参是红灯|黄灯|绿灯。 定义一个方法main(),main()内部执行:打印当前亮的灯就用setInterval每秒执行打印,红灯打印setTimeout 5s后打印黄灯,再setTimeout 2s后打印绿灯再setTimeout 3s后清除定时器调用自己进行循环。

实现源码


let timer = null
const printContent = (str) => {
  console.log(str)
}
const main = () => {
  printContent('红灯')

  clearInterval(timer)
  timer = setInterval(() => {
    printContent('红灯')
  }, 1000)

  setTimeout(() => {
    printContent('黄灯')
    clearInterval(timer)
    timer = setInterval(() => {
      printContent('黄灯')
    }, 1000)

    setTimeout(() => {
      printContent('绿灯')
      clearInterval(timer)
      timer = setInterval(() => {
        printContent('绿灯')
      }, 1000)

      setTimeout(() => {
        clearInterval(timer)
        main()
      }, 3000)
    }, 2000)
  }, 5000)
}
main()

方法2——Promise实现

思路

封装一个sleep方法:用来在指定的时间段,每秒打印指定内容,入参是:时间和打印的内容。 然后在main方法中使用promise的then回调依次执行红、黄、绿灯,绿灯之后再调用main方法继续循环。

实现源码

let timer = null
const printContent = (str) => {
  console.log(str)
}

const sleep = (time, light) => {
  return new Promise((resolve, reject) => {
    //printContent(light)
    clearInterval(timer)
    timer = setInterval(() => {
      printContent(light)
    }, 1000)
    setTimeout(resolve, time)
  })
}

const main = () => {
  sleep(5000, '红灯')
    .then(() => {
      return sleep(2000, '黄灯')
    })
    .then(() => {
      return sleep(3000, '绿灯')
    })
    .then(() => {
      main()
    })
    .catch(e => console.log(e))
}

main()

promise相对于setTimeout来说,明显的避免了“回调地狱”问题,但是 也有弊端,最明显的就是有很多then回调,使代码略显冗余,不够简洁和语义化。 ES2017 标准引入了 async 函数,它使得异步操作变得更加方便,接下来我们用async函数来实现一下这个红绿灯问题。

方法3——async/await实现

思路

封装一个sleep方法:用来在指定的时间段,每秒打印指定内容,入参是:时间和打印的内容。 和方法2的区别就是main方法,使用ES8的新特性,async/await实现异步。

实现源码

let timer = null
const printContent = (str) => {
  console.log(str)
}
const sleep = (time, light) => {
  return new Promise((resolve, reject) => {
    //printContent(light)
    clearInterval(timer)
    timer = setInterval(() => {
      printContent(light)
    }, 1000)
    setTimeout(resolve, time)
  })
}

const main = async () => {
  while (true) {
    await sleep(5000, '红灯')
    await sleep(2000, '黄灯')
    await sleep(3000, '绿灯')
    clearInterval(timer)
  }
}

main()

async函数实现起来代码很清爽,也提高了可读性,同时没有了被“回调地狱”支配的恐惧,避免了then回调的代码冗余,异步代码以同步的方式优雅的呈现了出来。

结语

如果有错别字或者不对的地方欢迎指出,将在第一时间改正,如果有更好的实现或想法希望留下你的评论 🔥