前言
每天见的红绿灯,红灯 3 秒、绿灯 2 秒、黄灯 1 秒的循环节奏,本质就是 JS 里经典的异步流程控制问题,也就是面试中的🚥红绿灯算法。今天咱们用极简的方式,给这个 “马路指挥家” 写段代码,让它规规矩矩按点 “上岗”。
一、先给红绿灯定个 “打工规则”
咱们先明确需求:红绿灯要按红→绿→黄的顺序循环亮灯,红灯工作 3 秒,绿灯 2 秒,黄灯 1 秒。核心难点在于 —— 必须等前一个灯亮完,下一个灯才能上岗,不能出现 “红绿同框” 的尴尬场面。
在 JS 里,要实现这种 “等一等再干活” 的逻辑,Promise是最佳拍档。先封装一个设置灯色和时长的函数,让每个灯的亮起都变成一个 “可等待” 的任务:
// 定义设置灯色的函数,返回Promise对象
function setColor(color, time) {
return new Promise((resolve, reject) => {
// 先打印当前灯的状态,告诉我们它要“上岗”多久
console.log(`${color}灯亮起,需要等${time/1000}秒`);
// 定时器模拟灯亮的时长,时间到了就“完成”这个任务
setTimeout(() => {
resolve(color); // 任务完成,返回当前灯色
}, time);
})
}
这个函数就像给红绿灯发了个 “工作通知”:告诉它要亮什么颜色、亮多久,等时间到了,就通知我们 “这个灯的活儿干完了”。
二、多方案实现:让红绿灯按节奏循环亮灯
写法 1:async/await—— 直白的 “指令式” 写法
async/await 是最贴近自然语言的写法,把异步流程写成同步逻辑:
// async/await实现循环亮灯
async function run() {
while(true) {
await setColor('红', 3000); // 等红灯亮完3秒
await setColor('绿', 2000); // 等绿灯亮完2秒
await setColor('黄', 1000); // 等黄灯亮完1秒
}
}
run();
await就是 “等一等”,只有前一个灯的任务完成,才会执行下一个,避免 “灯色串岗”。
写法 2:递归 + then 链 ——“接力式” 写法
这是 Promise 原生风格的写法,通过 then 链实现任务接力,递归完成无限循环:
// 递归+then链实现循环亮灯
function run() {
setColor('红', 3000).then(() => {
setColor('绿', 2000).then(() => {
setColor('黄', 1000).then(() => run()); // 黄灯结束后重新循环
})
})
}
run();
每个灯亮完后,通过 then 方法 “喊” 下一个灯上岗,最后递归调用 run () 重启整个流程。
写法 3:Promise 链 + 定时器 ——“手动计时循环” 写法
如果不想用递归,可以把完整的灯序封装成 Promise 链,再用 setInterval 定时执行:
// 定义完整的灯序执行函数
function lightSequence() {
return setColor('红', 3000)
.then(() => setColor('绿', 2000))
.then(() => setColor('黄', 1000));
}
// 按总时长(6秒)循环执行灯序
setInterval(lightSequence, 6000);
// 立即执行一次,避免首次等待6秒
lightSequence();
先定义「红→绿→黄」的完整 Promise 链,再用
setInterval 按总时长(3+2+1=6 秒)循环调用,注意要先手动执行一次,避免页面加载后首次需要等 6 秒才亮灯。
写法 4:生成器函数 + 自动执行 ——“迭代式” 写法
利用 ES6 的生成器函数(Generator)封装灯序逻辑,配合自动执行函数实现循环:
// 生成器函数定义灯序
function* lightGenerator() {
while(true) {
yield setColor('红', 3000);
yield setColor('绿', 2000);
yield setColor('黄', 1000);
}
}
// 自动执行生成器的函数
async function runGenerator() {
const gen = lightGenerator();
for await (const step of gen) {
// 自动迭代执行每个灯的任务
}
}
runGenerator();
结语
看似普通的红绿灯,藏着的是 JS 异步编程的核心逻辑:Promise 解决 “等待” 问题,async/await 或递归解决 “顺序 + 循环” 问题。
把抽象的代码和生活场景结合,面试的场景题其实不难 💪