1.使用Promise实现红绿灯交替重复亮
红灯3秒亮一次,绿灯2秒亮一次,黄灯1秒亮一次;如何让三个灯不断交替重复亮灯?
要求:用Promise实现
三个亮灯函数已经存在:
function red() {
console.log('red');
}
function green() {
console.log('green');
}
function yellow() {
console.log('yellow');
}
首先题目规定了使用promise那我们先用promise的方法来实现这个红绿灯交错。
首先我们会想到使用promise的链式调用+定时器,让交通灯按照红黄绿执行。
(function inifiteLight() {
return Promise.resolve()
.then(
new Promise((resolve) => {
red();
setTimeout(() => {
resolve();
}, 1000);
})
)
.then(
new Promise((resolve) => {
yellow();
setTimeout(() => {
resolve();
}, 2000);
})
)
.then(
new Promise((resolve) => {
green();
setTimeout(() => {
resolve();
}, 3000);
})
)
.then(inifiteLight());
})();
效果还是很不错的,再把中间公共的代码抽出来,最终效果如下:
function light(fn, time) {
return new Promise((resolve) => {
fn();
setTimeout(resolve, time);
});
}
(function inifiteLight() {
return Promise.resolve()
.then(light(red, 3000))
.then(light(yellow, 2000))
.then(light(green, 1000))
.then(inifiteLight());
})();
除此之外,我们思考,如果不使用promise,那么怎么让这三个灯按顺序执行并且无限循环呢?
可能我们首先会想到使用setInterval,是的,我们来尝试下~
正确用例✅:
setInterval(() => {
setTimeout(() => {
red();
}, 1000);
setTimeout(() => {
yellow();
}, 2000);
setTimeout(() => {
green();
}, 3000);
}, 3000);
实际上果然可行…那么接着我们把代码优化下:
const light = (fn, time) => {
setTimeout(fn, time);
};
setInterval(() => {
light(red, 1000);
light(yellow, 2000);
light(green, 3000);
}, 3000);
但是注意,setInterval的执行时间,一定要和setTimeout等待时间最长任务时间一致,比如:
如果我们把setInterval的执行时间设置为1000,则每1000ms会重新启一个定时器再重复执行,导致最终输出的log位置错乱,也就不能按想要的顺序执行了。
错误用例❌:
setInterval(() => {
setTimeout(() => {
red();
}, 1000);
setTimeout(() => {
yellow();
}, 2000);
setTimeout(() => {
green();
}, 3000);
}, 1000);
以上输出会顺序错乱~
那么问题来了,既然每次执行setInterval都会重新创建新的,当执行次数过多之后,肯定会造成内存泄漏。
那么我们如何优化呢?
我们可以想到2个方案:
- 控制setInterval执行后销毁,再去创建一个新的,保证永远只有一个setInterval在执行。
- 使用setTimeout的链式调用。
控制setInterval执行后销毁,第一个方案宣告失败❌
发生了预期之外的错误输出,我们的预期是red、yellow、green
function inifiteLight() {
let timer = setInterval(() => {
light(red, 1000);
light(yellow, 2000);
light(green, 3000);
if (timer) {
clearInterval(timer);
inifiteLight();
}
}, 1000);
}
inifiteLight();
使用setTimeout的链式调用,第二个方案可行✅
上代码,有点类似于promise的链式调用
function red() {
console.log("red");
}
function green() {
console.log("green");
}
function yellow() {
console.log("yellow");
}
function inifiteLight() {
setTimeout(() => {
red();
setTimeout(() => {
yellow();
setTimeout(() => {
green();
setTimeout(inifiteLight);
}, 1000);
}, 1000);
}, 1000);
}
inifiteLight();