自定义调度器通过加权任务队列控制微任务执行优先级,核心是重构任务提交与执行入口,用含weight/type/enqueuetime的task对象替代裸promise,并基于最小堆+requestidlecallback实现可控加权调度。

自定义调度器控制微任务执行权重,核心不是给每个 Promise 或 async 函数“加权”,而是重构任务提交与执行的入口,把权重语义注入到调度决策中——关键在“排队策略”和“出队时机”,而非运行时干预。
用带权重的任务封装替代裸 Promise
直接 return Promise.resolve() 无法参与调度控制。必须将业务逻辑包装为可排序、可延迟、可拦截的任务对象:
- 定义 Task 类,含 weight(数值越大越优先)、type(如 payment / report / sync)、enqueueTime(纳秒级冻结时间戳) 等只读字段
- 避免在 Task 构造或 compareTo 中调用异步操作、网络请求或锁;所有权重计算应在入队前完成
- 示例:支付回调任务 weight = 100,日志归档任务 weight = 10,两者共用同一调度器实例但天然分层
基于优先级队列实现加权出队逻辑
浏览器环境不提供原生加权队列,需手动组合:
- 使用 最小堆(Min-Heap)结构模拟优先级队列,按 -weight 排序(让高权值先出),相同 weight 时按 enqueueTime 升序防饥饿
- 不依赖 setTimeout(0) 模拟“立即执行”,而是统一通过 requestIdleCallback 或 postMessage 触发下一轮调度,确保可控性
- 在出队时做动态衰减:例如对已排队超 5 秒的任务,临时提升其有效 weight,防止低权任务长期积压
在 RxJS 中注入权重感知的调度行为
RxJS 的 Scheduler 接口本身不支持权重,但可通过扩展 schedule 方法实现:
- 继承 AsyncScheduler,重写 schedule(action, delay = 0, state?):将 state 扩展为 { fn, weight, groupId },内部存入加权队列
- 在队列 flush 阶段,按 weight 分组聚合,每组内按 FIFO 执行,组间按总 weight 加权轮询(如 weight=100 组每轮执行 2 个,weight=10 组每轮执行 1 个)
- 配合 Subject + scan 实现“权重透传”:上游 Observable 发射时携带 priority$ 流,下游 operator 自动绑定对应调度权重
规避常见陷阱
权重调度容易误入两个误区:
- 不修改正在运行的任务权重:Task 入队后 weight 必须 final;若需动态调权(如用户升级 VIP),应取消原任务并以新权重重新提交
- 不混淆调度权重与线程资源权重:前端无真实线程池,所谓“权重”仅影响宏/微任务队列中的相对位置,不能突破事件循环单线程本质
- 不依赖 performance.now() 实时计算:时间敏感型权重(如 SLA 倒计时)应基于任务创建时的 frozenTime 计算,避免出队时刻抖动










