红绿灯也内卷?用 JS 给马路 “指挥家” 写个打工脚本

0 阅读3分钟

前言

每天见的红绿灯,红灯 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);
    })
}

屏幕录制 2026-03-23 132454.gif

这个函数就像给红绿灯发了个 “工作通知”:告诉它要亮什么颜色、亮多久,等时间到了,就通知我们 “这个灯的活儿干完了”。

二、多方案实现:让红绿灯按节奏循环亮灯

写法 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();

屏幕录制 2026-03-23 132812.gif

每个灯亮完后,通过 then 方法 “喊” 下一个灯上岗,最后递归调用 run () 重启整个流程。

写法 3:Promise 链 + 定时器 ——“手动计时循环” 写法

如果不想用递归,可以把完整的灯序封装成 Promise 链,再用 setInterval 定时执行:

// 定义完整的灯序执行函数
function lightSequence() {
    return setColor('红', 3000)
        .then(() => setColor('绿', 2000))
        .then(() => setColor('黄', 1000));
}
// 按总时长(6秒)循环执行灯序
setInterval(lightSequence, 6000);
// 立即执行一次,避免首次等待6秒
lightSequence();

屏幕录制 2026-03-23 133350.gif 先定义「红→绿→黄」的完整 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();

屏幕录制 2026-03-23 133814.gif

结语

看似普通的红绿灯,藏着的是 JS 异步编程的核心逻辑:Promise 解决 “等待” 问题,async/await 或递归解决 “顺序 + 循环” 问题。

把抽象的代码和生活场景结合,面试的场景题其实不难 💪