5月27日 21:25

RxJS 中的调度器(Scheduler)是什么?如何使用?

调度器是什么

调度器决定 RxJS 中通知(next/error/complete)的执行时机和上下文。简单说:它控制一段 Observable 逻辑"在什么时候跑"——同步、微任务、宏任务还是动画帧。

RxJS 内置 5 种调度器,核心区别如下:

调度器底层机制典型场景
null(同步)直接递归调用默认,少量数据
queueScheduler同步蹦床调度递归/迭代,防栈溢出
asapSchedulerPromise.then(微任务)优先级高于宏任务的异步
asyncSchedulersetInterval(宏任务)延迟、定时操作
animationFrameSchedulerrequestAnimationFrame浏览器动画

怎么指定调度器

三种方式:

1. 创建时传入——作为操作符最后一个参数:

typescript
of(1, 2, 3, asyncScheduler).subscribe(console.log);

2. observeOn / subscribeOn

  • observeOn(asyncScheduler):下游通知切到异步调度
  • subscribeOn(asyncScheduler):上游订阅动作切到异步调度

二者区别常被追问:subscribeOn 影响的是"什么时候开始执行 Observable 逻辑",observeOn 影响的是"下游在哪个调度器上接收通知"。

3. schedule 方法——手动调度:

typescript
asyncScheduler.schedule(() => console.log('1s后'), 1000);

面试高频追问

asapScheduler 和 asyncScheduler 有什么区别?

asapScheduler 走微任务队列(Promise.then),asyncScheduler 走宏任务队列(setTimeout/setInterval)。微任务优先级更高,会在当前宏任务结束后、下一个宏任务之前执行。需要尽快响应但不阻塞主线程时选 asap,需要真正延迟时选 async。

queueScheduler 和同步调度器有什么区别?

同步调度器直接递归调用,大量数据可能栈溢出。queueScheduler 用蹦床调度(trampoline),把递归展开为循环迭代,避免栈溢出同时保持同步语义。

什么时候该手动指定调度器?

大多数时候不需要——RxJS 按最小并发原则自动选择默认调度器。手动指定主要出现在三个场景:测试中用 TestScheduler 控制时间、动画中用 animationFrameScheduler 同步渲染帧、需要改变默认执行上下文时。

如何在测试中控制调度器?

使用 TestScheduler,它提供虚拟时钟,可以用 marble diagram 声明时序并同步断言结果,避免真实等待。

选择建议

不需要调度器就不加。需要延迟选 async,需要非阻塞优先级选 asap,递归防溢出选 queue,动画选 animationFrame。过度使用调度器只会增加复杂度和性能开销。

标签:Rxjs