陌小路的个人博客 陌小路的个人博客
首页
  • 技术专区

    • 面试
    • Vue
    • Electron
    • TypeScript
    • Serverless
    • GraphQL
  • 我的秋招之旅
  • 2019年终总结
Todo
收藏夹
关于作者
GitHub

陌小路

前端切图仔
首页
  • 技术专区

    • 面试
    • Vue
    • Electron
    • TypeScript
    • Serverless
    • GraphQL
  • 我的秋招之旅
  • 2019年终总结
Todo
收藏夹
关于作者
GitHub
  • Vue

  • React

  • 面试

  • Electron

  • Serverless

  • GraphQL

  • TypeScript

  • RxJS

    • 介绍
    • 前置知识点
    • Observable
    • Observer
    • Subscription与Subject
    • Cold-Observables与Hot-Observables
    • Schedulers
    • Operators概念
    • 创建型Operators
    • 转换操作符
    • 过滤操作符
    • 组合操作符
    • 总结
  • 工程化

  • Webpack

  • Nestjs

  • WebRTC & P2P

  • Docker

  • Linux

  • Git

  • Svelte

  • 踩坑日记 & 小Tips

  • 其他

  • technology
  • RxJS
陌小路
2020-12-22

Schedulers(调度器)

用来控制并发并且是中央集权的调度员,允许我们在发生计算时进行协调,例如 setTimeout 或 requestAnimationFrame 或其他。

  • 调度器是一种数据结构。 它知道如何根据优先级或其他标准来存储任务和将任务进行排序。
  • 调度器是执行上下文。 它表示在何时何地执行任务(举例来说,立即的,或另一种回调函数机制(比如 setTimeout 或 process.nextTick),或动画帧)。
  • 调度器有一个(虚拟的)时钟。 调度器功能通过它的 getter 方法 now() 提供了“时间”的概念。在具体调度器上安排的任务将严格遵循该时钟所表示的时间。

学到这相信大家也已经或多或少对RxJS有一定了解了,不知道大家有没有发现一个疑问,前面所展示的代码示例中有同步也有异步,而笔者却没有显示的控制他们的执行,他们的这套执行机制到底是什么呢?

其实他们的内部的调度就是靠的Schedulers来控制数据发送的时机,许多操作符会预设不同的Scheduler,所以我们不需要进行特殊处理他们就能良好的进行同步或异步运行。

const source = Rx.Observable.create(function (observer: any) {
    observer.next(1);
    observer.next(2);
    observer.next(3);
    observer.complete();
});

console.log('订阅前');
source.observeOn(Rx.Scheduler.async) // 设为 async
.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});
console.log('订阅后');

// 订阅前
// 订阅后
// 1
// 2
// 3
// complete
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

从打印结果上来看,数据的发送时机的确已经由同步变成了异步,如果不进行调度方式修改,那么“订阅后”的打印应该是在数据发送完毕之后才会执行的。

看完示例之后我们再来研究这个调度器能做哪几种调度:

  • queue
  • asap
  • async
  • animationFrame

# queue

将每个下一个任务放在队列中,而不是立即执行

queue 延迟使用调度程序时,其行为与 async 调度程序相同。

当没有延迟使用时,它将同步安排给定的任务-在安排好任务后立即执行。但是,当递归调用时(即在已调度的任务内部),将使用队列调度程序调度另一个任务,而不是立即执行,该任务将被放入队列并等待当前任务完成。

这意味着,当您使用 queue 调度程序执行任务时,您确定它会在该调度程序调度的其他任何任务开始之前结束。

这个同步与我们平常理解的同步可能不太一样,笔者当时也都困惑了一会。

还是用一个官方的例子来讲解这种调度方式是怎么理解吧:

import { queueScheduler } from 'rxjs';
queueScheduler.schedule(() => {
  queueScheduler.schedule(() => console.log('second'));

  console.log('first');
});
1
2
3
4
5
6

我们无需关注陌生的函数调用,我们这里着重于看这种调度方式与平常的同步调度的区别。

首先我们调用queueScheduler的schedule方法开始执行,然后函数内部又同样再以同样的方式调用(这里也可以改成递归,不过这里用这个示例去理解可能会好一点),并且传入一个函数,打印second。

然后继续看下面的语句,一个普通的console.log('first'),然后我们再来看看打印结果:

// first
// second
1
2

是不是有点神奇,如果没看明白为啥的,可以再回头看看前面queue对于递归执行的处理方式。也就是说如果递归调用,它内部会维护一个队列,然后等待先加入队列的任务先执行完成(也就是上面的console.log('first')执行完才会执行console.log('second'),因为console.log('second')这个任务是后加入该队列的)。

# asap

内部基于Promise实现(Node端采用process.nextTick),他会使用可用的最快的异步传输机制,如果不支持Promise或process.nextTick或者Web Worker的 MessageChannel也可能会调用setTimeout方式进行调度。

# async

与asap方式很像,只不过内部采用setInterval进行调度,大多用于基于时间的操作符。

# animationFrame

从名字看其实相信大家已经就能略知一二了,内部基于requestAnimationFrame来实现调度,所以执行的时机将与window.requestAnimationFrame保持一致,适用于需要频繁渲染或操作动画的场景。

编辑
上次更新: 2023/11/25, 4:11:00
Cold-Observables与Hot-Observables
Operators概念

← Cold-Observables与Hot-Observables Operators概念→

最近更新
01
github加速
01-01
02
在线小工具
01-01
03
Lora-Embeddings
11-27
更多文章>
Theme by Vdoing | Copyright © 2020-2024 STDSuperman | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式