前几天遇到一道有意思的题目。
大意是用 async 和 await 实现一个红绿灯。红灯停 5s、绿灯 10s、黄灯 3s。
扩展:支持手动切换当前灯的状态
非扩展部分很简单,实现一个 sleep 就 OK 了。但是扩展部分很好玩。
本身 Promise 就是 Micro Queue 的实现;所以初步我打算用 queue 实现,正在考虑队列的防饿死问题时,我意识到实效性的问题。
即便我把红灯手动入队,但是我渲染的还是当前出队的灯,会导致延迟的问题。
如果我渲染的队首,然后轮训出队。不断入队。则需求考虑队满了之后的策略。
所以我认为 Queue 不是首选的结构。我最后采用了状态链表实现。
节点
1
2
3
4
5
6
7
8
9
10
|
class Node {
public color: string;
public delay: number;
next: Node | null = null;
constructor({ color, delay }: { color: string; delay: number }) {
this.color = color;
this.delay = delay;
}
}
|
节点很简单,保存一些 payload 即可
链表实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
class Ring {
private head: Node | null;
private timer: number = 0;
public onNext?: (n: Node | null) => void;
constructor() {
this.head = null;
}
set(n: Node) {
this.head = n;
}
reset(n: Node) {
this.stop();
this.set(n);
this.onNext?.(n);
this.poll();
}
poll() {
if (this.head) {
this.timer = window.setTimeout(() => {
this.next();
this.poll();
}, this.head?.delay);
}
}
stop() {
clearTimeout(this.timer);
}
next() {
this.head = this.head?.next ?? null;
this.onNext?.(this.head ?? null);
}
}
|
其中 reset 方法用于实现手动控制功能。
下面我们看下如何使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
const red = new Node({ color: 'red', delay: 5000 }),
yellow = new Node({ color: 'yellow', delay: 3000 }),
green = new Node({ color: 'green', delay: 10000 });
red.next = yellow;
yellow.next = green;
green.next = red;
const ring = new Ring();
export default () => {
const [curNode, setCurNode] = useState<Node | null>(red);
useEffect(() => {
ring.set(red);
ring.onNext = setCurNode;
ring.poll();
return () => {
ring.stop();
};
}, []);
return (
<>
{curNode?.color}
<br />
<button onClick={() => {ring.reset(red)}}>
red
</button>
<button onClick={() => {ring.reset(yellow)}}>
yellow
</button>
<button onClick={() => {ring.reset(green)}}>
green
</button>
</>
);
};
|
总结
总结下用链表的好处:
- 每个灯(Node)相对独立。复用性高。我可以new 5s的黄灯 10s的黄灯 20s的黄灯应对不同的场景;
- 更灵活的运行时(runtime)编排;
- 更好的可读、可维护性。