突然想起来之前我面试时候的一道面试题,用js实现一个红绿灯,想想当时发挥的不如人意,今天就来回顾复习一下。
题目
红灯持续5s,黄灯2s,绿灯3s,红灯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回调的代码冗余,异步代码以同步的方式优雅的呈现了出来。