惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
J
Java Code Geeks
爱范儿
爱范儿
雷峰网
雷峰网
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 三生石上(FineUI控件)
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog RSS Feed
Google DeepMind News
Google DeepMind News
Jina AI
Jina AI
The GitHub Blog
The GitHub Blog
I
InfoQ
月光博客
月光博客
博客园 - 聂微东
博客园 - Franky
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
G
Google Developers Blog
Blog — PlanetScale
Blog — PlanetScale
L
LangChain Blog
罗磊的独立博客
Apple Machine Learning Research
Apple Machine Learning Research

Coding Your Life

lib库开发的一款PDF处理小工具 | Coding Your Life mirror-cli | Coding Your Life 最长递增子序列算法 | Coding Your Life webpack5 模块联邦技术 | Coding Your Life webpack基础配置详解 | Coding Your Life canvas实现代码雨效果 | Coding Your Life vue3 和 react 虚拟dom | Coding Your Life ES6中Reflect对象与Proxy结合实现代理和响应式编程 | Coding Your Life 前端技术分享MediaRecord实现运动相机 | Coding Your Life react基础概念 | Coding Your Life 微信小程序使用canvas创建像素头像 | Coding Your Life 前端基础概念 | Coding Your Life 中高级前端须注意的40条移动端H5坑位指南 | Coding Your Life native-code-push 热更新配置 | Coding Your Life Git 常用命令速查表 | Coding Your Life push-server 热更新常用命令速查表 | Coding Your Life 高效的js片段 | Coding Your Life
使用MessageChannel模拟React优先级执行队列 | Coding Your Life
Sir_Liu · 2025-05-23 · via Coding Your Life

前言

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.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 }

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