更新:增加使用 async/await
以及箭头函数的重构代码
问题
红灯三秒亮一次,绿灯一秒亮一次,黄灯2秒亮一次;如何让三个灯按照这个规律不断交替重复亮灯?(用Promse实现)三个亮灯函数已经存在:
function green() {
console.log("green");
}
function yellow() {
console.log("yellow");
}
function red() {
console.log("red");
}
#思路解析
一道经典的考察 promise 应用的面试题
我们要解决两个问题,思路如下
###1 控制每盏灯,使其按某节奏闪烁
- 命名为 flash 函数,参数为亮灯函数与时间参数
- 应该会用到计时器
###2 控制三种灯闪烁的顺序
- 命名为 control 函数。
- 应该会用到promise,链式调用。
###3 实现重复不断的循环
- 递归
- 为什么不能使用 while 等实现无限循环
#代码演进
实现一次周期内的闪烁
通过上面 1、2 两点,可以得到如下代码
function flash(cb, time) {}
function control() {
Promise.resolve()
.then()
.then()
.then()
}
对于 control
函数
promise.then() 方法:
- 期望的参数为函数
- 返回的结果是一个promise
故而,then 方法的参数函数为
function() {
return flash(red, 3000);
}
control
函数整体为
function control(promise) {
promise
.then(function() {
return flash(red, 3000);
})
.then(function() {
return flash(green, 1000);
})
.then(function() {
return flash(yellow, 2000);
});
}
flash
函数
由上可知,它应该返回一个完成态的 promise。
由于要结合定时器使用,采用promise构造函数的写法,代码如下
function flash(cb, time) {
return new Promise(function executor(resolve, reject) {
setTimeout(() => {
cb(), resolve();
}, time);
});
}
目前,已经实现了一个周期内的亮灯控制。
实现重复闪烁
要实现不断重复,考虑递归
为什么 while
不行
当然,说到无限循环,很容易想到 while
循环等方法。事实上,这种办法行不通。这涉及到 JavaScript 异步运行机制,参考 单线程 JavaScript 的异步机制与经典 for 循环面试题 。
简单地说
-
一次 事件循环 中,同步代码先入 执行栈 执行,异步代码分情况将其任务注册到 任务队列 中。
-
只有执行栈清空,主线程 才会从任务队列中读取任务,使其入栈执行
-
类似
while(true)
这样的代码,会永久占据主线程,使得执行栈永远不清空。 -
所以,任务队列中等待的亮灯任务也就永无出头之日。
递归
灯光闪烁一个周期,即 control
函数运行一次之后,让 control
函数递归调用自身即可。
还是用 then 方法控制流程,加一个 .then()
,其参数按规定是一个函数,在该匿名函数内部调用函数本身,实现递归。
control
函数最终如下
function control() {
Promise.resolve()
.then(function() {
return flash(red, 3000);
})
.then(function() {
return flash(green, 1000);
})
.then(function() {
return flash(yellow, 2000);
})
.then(function() {
control();
});
}
#完整代码
function green() {
console.log("green");
}
function yellow() {
console.log("yellow");
}
function red() {
console.log("red");
}
function flash(cb, time) {
return new Promise(function executor(resolve, reject) {
setTimeout(() => {
cb(), resolve();
}, time);
});
}
function control() {
Promise.resolve()
.then(function() {
return flash(red, 3000);
})
.then(function() {
return flash(green, 1000);
})
.then(function() {
return flash(yellow, 2000);
})
.then(function() {
control();
});
}
control();
重构
const red = () => console.log('red')
const green = () => console.log('green')
const yellow = () => console.log('yellow')
const controlLight = color => time => (
new Promise((resolve, reject) => {
setTimeout(() => {
color()
resolve()
}, time)
})
)
const controlOrder = async () => {
await controlLight(red)(3000)
await controlLight(green)(1000)
await controlLight(yellow)(2000)
await controlOrder()
}
controlOrder()