30 天精通 RxJS(28):Scheduler 基本观念

转载
不晓得读者们还记不记得,我们在前面的文章中有提到 Scheduler 是为了解决 RxJS 衍生的最后一个问题,而我们现在就在揭晓这个谜底。

其实 RxJS 用久了之后就会发现 Observable 有一个优势是可以同时处理同步和非同步行为,但这个优势也带来了一个问题,就是我们常常会搞不清处现在的 observable 执行方式是同步的还是非同步的。换句话说,我们很容易搞不清楚 observable 到底什麽时候开始发送元素!

举例来说,我们可能很清楚 interval 是非同步送出元素的,但 range 呢? from呢?他们可能有时候是非同步有时候是同步,这就会变得有点困扰,尤其在除错时执行顺序就非常重要。

而 Scheduler 基本上就是拿来处理这个问题的!

什麽是 Scheduler?

Scheduler 控制一个 observable 的订阅什麽时候开始,以及发送元素什麽时候送达,主要由以下三个元素所组成

  • Scheduler 是一个资料结构。 它知道如何根据优先级或其他标准来储存并伫列任务。
  • Scheduler 是一个执行环境。 它意味著任务何时何地被执行,比如像是 立即执行、在回呼(callback)中执行、setTimeout 中执行、animation frame 中执行
  • Scheduler 是一个虚拟时钟。 它透过 now() 这个方法提供了时间的概念,我们可以让任务在特定的时间点被执行。

简言之 Scheduler 会影响 Observable 开始执行及元素送达的时机,比如下面这个例子

var observable = Rx.Observable.create(function (observer) {
    observer.next(1);
    observer.next(2);
    observer.next(3);
    observer.complete();
});

console.log('before subscribe');
observable.observeOn(Rx.Scheduler.async) // 设为 async
.subscribe({
    next: (value) => { console.log(value); },
    error: (err) => { console.log('Error: ' + err); },
    complete: () => { console.log('complete'); }
});
console.log('after subscribe');

// "before subscribe"
// "after subscribe"
// 1
// 2
// 3
// "complete"

JSBin

上面这段程式码原本是同步执行的,但我们用了 observable.observeOn(Rx.Scheduler.async) 原本是同步执行的就变成了非同步执行了。

有哪些 Scheduler 可以用

目前 RxJS 5 Scheduler 跟 RxJS 4.x 以前的版本完全不同,在 RxJS 5 当中有提供四个 scheduler,预设为 undefined 会直接以递回的方式执行

  • queue
  • asap
  • async
  • animationFrame

这四个 scheduler 我们会在下面搭配程式码一一讲解

RxJS 5 跟 RxJS 4.x 预设的 Scheduler 不同,所以在某些使用情境下会出现不同的结果,例如这个 issue,请特别注意。

使用 Scheduler

其实我们在使用各种不同的 operator 时,这些 operator 就会各自预设不同的 scheduler,例如一个无限的 observable 就会预设为 queue scheduler,而 timer 相关的 operator 则预设为 async scheduler。

要使用 Scheduler 除了前面用到的 observeOn() 方法外,以下这几个 creation operators 最后一个参数都能接收 Scheduler

  • bindCallback
  • bindNodeCallback
  • combineLatest
  • concat
  • empty
  • from
  • fromPromise
  • interval
  • merge
  • of
  • range
  • throw
  • timer

例如下面这个例子

var observable = Rx.Observable.from([1,2,3,4,5], Rx.Scheduler.async);

另外还有多个 operators 最后一个参数可以传入 Scheduler 这边就不一一列出,这已参考官方的文件,最通用的方式还是 observeOn() 只要是 observable 就可以用这个方法。

queue

queue 的运作方式跟预设的立即执行很像,但是当我们使用到递回的方法时,他会伫列这些行为而非直接执行,一个递回的 operator 就是他会执行另一个 operator,最好的例子就是 repeat(),如果我们不给他参数的话,他会执行无限多次,像下面这个例子

Rx.Observable.of(10).repeat().take(1)
.subscribe(console.log);

这个例子在 RxJS 4.x 的版本中执行会使浏览器挂掉,因为 take(1) 永远不会被执行到 repeat 会一直重複要元素,而在 RxJS 5 中他预设了无限的 observable 为 queue 所以他会把 repeat 的 next 行为先伫列起来,因为前一个 complete 还在执行中,而这时 repeat 就会回传一个可退订的物件给 take(1) 等到 repeat 的 next 被第一次执行时就会结束,因为 take(1) 会直接收到值。

使用情境:

queue 很适合用在会有递回的 operator 且具有大量资料时使用,在这个情况下 queue 能避免不必要的效能损耗。

asap

asap 的行为很好理解,它是非同步的执行,在浏览器其实就是 setTimeout 设为 0 秒 (在 NodeJS 中是用 process.nextTick),因为行为很好理解这裡就不写例子了。

使用情境:

asap 因为都是在 setTimeout 中执行,所以不会有 block event loop 的问题,很适合用在永远不会退订的 observable,例如在背景下持续监听 server 送来的通知。

async

这个是在 RxJS 5 中新出现的 Scheduler,它跟 asap 很像但是使用 setInterval 来运作,通常是跟时间相关的 operator 才会用到。

animationFrame

这个相信大家应该都知道,他是利用 Window.requestAnimationFrame 这个 API 去实作的,所以执行週期就跟 Window.requestAnimationFrame 一模一样。

使用情境:

在做複杂运算,且高频率触发的 UI 动画时,就很适合使用 animationFrame,以可以搭配 throttle operator 使用。

今日小结

这篇文章简单的介绍了 RxJS 的 Scheduler,因为篇幅的关系没有办法很细的去讲,但实务上 Scheduler 的使用非常简单,只要在 operator 的最后一个参数加上去或是用 observeOn 就可以了。平常其实不太需要用到 Scheduler,尤其在 RxJS 5 中已经有针对各种情况给不同的预设,笔者最常用到的还是 animationFrame!

不知道今天读者们有没有收穫呢? 如果有任何疑问,欢迎在下方留言给我,谢谢。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容

  • 介绍 RxJS是一个异步编程的库,同时它通过observable序列来实现基于事件的编程。它提供了一个核心的类型:...
    泓荥阅读 16,581评论 0 12
  • 我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy阅读 5,456评论 7 62
  • 来自于:CSDNblog.csdn.net/caihongdao123/article/details/51897...
    于加泽阅读 1,254评论 0 5
  • 女孩和妈妈捧着从山谷流出来的泉水,一股热流袭来,裹住她的双手,它是暖的,她们欣喜若狂,抱在一起,说:“我知道...
    袁小暖阅读 317评论 0 0