使用MessageChannel模拟React优先级执行队列

前言

MessageChannelHTML5window 对象提供的一个用于跨线程通信的 API,它允许我们在不同的浏览上下文(如主线程与 Worker 线程)之间传递数据。React 利用了 MessageChannel 来实现优先级任务调度,模拟异步任务队列。

以下是关于 MessageChannel 的关键点:

MessageChannel 创建两个端口 (port1, port2),它们可以互相发送消息。
在 React 的调度器中,使用 MessageChannel 将低优先级任务延迟执行,而高优先级任务可以中断低优先级任务。
通过 port.postMessage() 将任务加入队列,通过监听 message 事件来触发任务执行。
相比 setTimeoutMessageChannel 提供了更细粒度的控制,并且在浏览器中具有更高的优先级。
示例代码如下:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

enum ScheduleType {
event = 1000,
timeout = 2000,
}
type ScheduleItem = {
time: number,
callback: Function
}

class SimpleSchedule {
private queue: Array<any> = [];
private port1: MessagePort;
private port2: MessagePort;
private isRunning: boolean = false;
constructor() {

const channel = new MessageChannel();
this.port1 = channel.port1;
this.port2 = channel.port2;
// 这里必须要绑定this
this.onSchedule = this.onSchedule.bind(this);
this.port1.onmessage = this.onSchedule;
}
onSchedule(){
console.log('开始执行了')
this.queueLoop();
}
dispatchMsg(){
this.port2.postMessage(null);
}
schedule(fn: Function, scheduleType: ScheduleType){
const time = performance.now() + scheduleType;
this.push({callback: fn, time });
if(!this.isRunning){
this.isRunning = true;
this.dispatchMsg();
}

}
push(schedule: ScheduleItem){
this.queue.push(schedule);
this.queue.sort((a,b)=>a.time - b.time);
}
pop(){
return this.queue.shift()
}
queueLoop(){
let schedule = this.pop();
while(schedule){
schedule.callback();
schedule = this.pop();
}
this.isRunning = false;
}
}
const simpleSchedule = new SimpleSchedule();

simpleSchedule.schedule(()=>{
console.log('schedule 1');
},ScheduleType.timeout);

simpleSchedule.schedule(()=>{
console.log('schedule 2');
},ScheduleType.event);
// 打印结果:
开始执行了
schedule 2
schedule 1

上述代码中,SimpleSchedule类是一个简单的调度器,用于管理多个任务。它使用一个队列来保存任务,并使用一个isRunning属性来指示当前是否正在执行任务。

ts文件可以直接用ts-node运行,如果报错TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for...... 请在ts-connfig中添加"ts-node": { "esm": true }

今天的分享就到这了,如有疑问🤔️评论区见

文章作者: Sir_Liu
文章链接: https://gofugui.github.io/2025/05/23/使用MessageChannel模拟React优先级执行队列/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Coding Your Life