「这是我参与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回调的代码冗余,异步代码以同步的方式优雅的呈现了出来。
结语
如果有错别字或者不对的地方欢迎指出,将在第一时间改正,如果有更好的实现或想法希望留下你的评论 🔥