SOURCE

const serial = ['Red', 'Yellow', 'Green'] //交通灯 颜色 顺序

function delay(duration = 1000) {
    return new Promise(reesovle => {
        setTimeout(reesovle, duration)
    })
}

class Signal {
    constructor(option) {
        this.sig = option.init //初始化当前信号灯颜色
        this.times = option.times //初始化每个信号灯颜色持续时间
        this.setTime() //运行第一次 设置信号灯什么时间结束
        this.exchange() //运行第一次监听
    }
    // 获取下一个灯 颜色
    get next() {
        // 此处交通灯颜色顺序数组的元素值与sig相等,所以使用indexOf函数找到此时的下标
        // 得到此时下标+1,然后对交通灯颜色数量取余的值就是下一个灯的下标
        // 例如 此时 是 Red 灯,在数组中下标0,物理顺序为 1,1%3取余,为1,1就是下一个灯的数组下标
        let nextSig = serial[(serial.indexOf(this.sig) + 1) % serial.length]
        return nextSig
    }
    // 获取当前灯 剩余时间
    get remain() {
        let diff = this.end - Date.now() // 使用提前获取的 当前灯结束时间 - 当前的系统时间 即可得到剩余时间
        if (diff < 0) {
            diff = 0
        }
        return diff / 1000
    }
    // 监听是否需要切换,内部自我调用,持续运行这个函数实现监听
    async exchange() {
        if (this.remain > 0) {
            // 不需要切换
            await delay(1000)
            console.log(this.remain)// 打印每秒钟下的剩余时间
        } else {
            // 切换信号灯
            this.sig = this.next
            this.setTime()
            console.log('信号灯切换', this.sig)
        }
        this.exchange()
    }

    // 设置当前灯 应该在什么时间戳 结束
    setTime() {
        this.start = Date.now()
        const time = this.times[serial.indexOf(this.sig)]
        this.end = this.start + time * 1000
    }
}

const s = new Signal({
    init: 'Red',
    times: [10, 3, 5]
})
s
console 命令行工具 X clear

                    
>
console