前言 MessageChannel 是 HTML5 中 window 对象提供的一个用于跨线程通信的 API,它允许我们在不同的浏览上下文(如主线程与 Worker 线程)之间传递数据。React 利用了 MessageChannel 来实现优先级任务调度,模拟异步任务队列。
以下是关于 MessageChannel 的关键点:
MessageChannel 创建两个端口 (port1, port2),它们可以互相发送消息。 在 React 的调度器中,使用 MessageChannel 将低优先级任务延迟执行,而高优先级任务可以中断低优先级任务。 通过 port.postMessage() 将任务加入队列,通过监听 message 事件来触发任务执行。 相比 setTimeout ,MessageChannel 提供了更细粒度的控制,并且在浏览器中具有更高的优先级。 示例代码如下:
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 }
今天的分享就到这了,如有疑问🤔️评论区见