携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
Scheduler调度器控制着何时启动 subscription 和何时发送通知。它由三部分组成:
- 调度器是一种数据结构。 它知道如何根据优先级或其他标准来存储任务和将任务进行排序。
- 调度器是执行上下文。 它表示在何时何地执行任务(举例来说,立即的,或另一种回调函数机制(比如 setTimeout 或 process.nextTick),或动画帧)。
- 调度器有一个(虚拟的)时钟。 调度器功能通过它的 getter 方法 now() 提供了“时间”的概念。在具体调度器上安排的任务将严格遵循该时钟所表示的时间。
调度器可以让你规定 Observable 在什么样的执行上下文中发送通知给它的观察者。
const { Observable, asyncScheduler, subscribeOn } = require('rxjs');
const ob$ = new Observable((observer) => {
observer.next(1);
observer.next(2);
observer.next(3);
observer.complete();
});
console.log('Start...');
// 新语法
ob$.pipe(subscribeOn(asyncScheduler, 2000)).subscribe((data) => {
console.log(data);
});
console.log('End...');
Start...
End...
1
2
3
基本原理:asyncScheduler调度器应该是使用了setTimeout或setInterval,所以它会在下一次事件循环中运行,也就是说它是异步的。至于顶层是用setTimeout还是用setInterval来实现,请关注我后面原理部分的文章,会有详细的分析。
调度器都有哪些类型呢?也可以不使用调度器哦。
null
不使用调度器。
asyncScheduler
异步调度器:异步执行任务,可以指定延迟时间。就像你使用过的 setTimeout(task, duration) 那样调度任务。
const { Observable, asyncScheduler, subscribeOn } = require('rxjs');
asyncScheduler.schedule(() => {
console.log('async');
});
console.log('End');
// End
// async
asyncScheduler.schedule((data) => {
console.log('async', data);
},0, 666);
console.log('End');
// End
// async 666
asapScheduler
asapScheduler是尽可能快的异步地执行任务。当你用它来延时任务的时候,asap 调度器的行为和 async 一样。如果你将延时时间设置为 0, asap 会等待当前同步执行结束然后立刻执行当前任务。asap 会尽全力最小化当前执行代码和开始调度任务的时间。这使得它成为执行“deferring”的最佳方式。以前,可以通过 调用 setTimeout(deferredTask, 0) 来做到,但是这种方式仍热包含一些非期望的延时。
注意,使用 asap 调度器并不一定意味着你的任务将会在当前执行代码后第一个执行。尤其是如果之前有其他 asap 调度器的 任务,该任务会首先执行。也就是说,如果你需要异步地调用任务,但是尽可能快的执行,asap 调度器是你最好的选择。
思考: 下面的代码,asapScheduler会先执行,底层是怎么实现的呢?也就是后面的任务先于前面的任务执行。
asyncScheduler.schedule(() => {
console.log('async');
}, 0);
asapScheduler.schedule(() => {
console.log('asap');
}, 0);
async VS asap
const { Observable, asyncScheduler,asapScheduler } = require('rxjs');
asyncScheduler.schedule(() => {
console.log('async');
}, 0);
asapScheduler.schedule(() => {
console.log('asap');
}, 0);
// asap
// async
queueScheduler
队列调度器。将每个任务都放到队列里,而不是立刻执行它们。
queue延迟调度程序时,其行为和async调度程序是相同的。
当没有延迟时,它将同步安排给定的任务。但是当递归调用时,将使用队列调度程序调度另一个任务,而不是立即执行,该任务将放入队列并等待当前任务完成。
这意味着,当您使用 queue 调度程序执行任务时,你确定它会在该调度程序调度的其他任何任务开始之前结束。
const { Observable, queueScheduler, subscribeOn } = require('rxjs');
queueScheduler.schedule((data) => {
console.log('queue', data);
}, 0, 666);
console.log('End');
// queue 666
// End
const { Observable, queueScheduler, subscribeOn } = require('rxjs');
queueScheduler.schedule((data) => {
console.log('queue', data);
},1000, 666);
console.log('End');
// End
// queue 666
const { queueScheduler } = require('rxjs');
queueScheduler.schedule(() => {
queueScheduler.schedule(() => console.log('second'));
console.log('first');
});
console.log('End');
// first
// Second
// End
第三个例子,可以看出在递归的情况下,会有一个queue,这也就是为什么叫queueScheduler的原因吧。
animationFrameScheduler
animationFrameScheduler叫动画帧调度器。看到这个调度器,想到了两个window上的API,requestIdleCallback,requestAnimationFrame,这两个API是和浏览器的绘制帧有关系的,其实Rxjs的这些调度器的异步性底层都是由异步函数来实现的异步。这里的animationFrameScheduler是,当requestAnimationFrame执行的时候触发执行此任务,适用于需要频繁渲染或操作动画的场景。
关于animationFrameScheduler就不详细介绍了,使用场景并不多。建议先从window上的两个API requestIdleCallback,requestAnimationFrame入手,这两个API有个一定的了解,自然轻轻松松掌握animationFrameScheduler。