Help us understand the problem. What is going on with this article?

先取りRxJS v7 (alpha.1)

:warning: この記事は現時点でv7.0.0-alpha.1が出ている、正式リリース前のRxJS v7について扱っている

RxJS v7の大きめな変更点

  • scheduled が追加
  • v6でdeprecatedだった一部Operatorsの扱い変更
  • 型の強化
  • TestScheduler の変化

scheduled が追加

scheduled はCreation Functionのひとつ。次のようにimportして使う。

import { scheduled } from 'rxjs';

scheduled の追加に伴い、一部Creation FunctionsおよびOperatorsにて、schedulerを受け取るシグネチャが(v6.5の時点で)deprecatedになっている。書き換えが必要になるが、基本的にスケジューラーを酷使していなければ、後述するパターンはそもそも必要ないことを覚えておいてほしい。

対象と動作を維持した書き換え例は次の通り:

Creation Functions

of

// before(deprecated)
import { of, asyncScheduler } from 'rxjs';

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

// after
import { scheduled, asyncScheduler } from 'rxjs';

scheduled([1, 2, 3], asyncScheduler).subscribe(console.log);

from

// before(deprecated)
import { from, asyncScheduler } from 'rxjs';

from([1, 2, 3], asyncScheduler).subscribe(console.log);

// after
import { scheduled, asyncScheduler } from 'rxjs';

scheduled([1, 2, 3], asyncScheduler).subscribe(console.log);

concat

// before(deprecated)
import { of, concat, asyncScheduler } from 'rxjs';

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

// after
import { of, scheduled, asyncScheduler } from 'rxjs';
import { concatAll } from 'rxjs/operators';

scheduled([of(1), of(2), of(3)], asyncScheduler)
  .pipe(
    concatAll()
  )
  .subscribe(console.log);

merge

// before(deprecated)
import { of, merge, asyncScheduler } from 'rxjs';

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

// after
import { of, scheduled, asyncScheduler } from 'rxjs';
import { mergeAll } from 'rxjs/operators';

scheduled([of(1), of(2), of(3)], asyncScheduler)
  .pipe(
    mergeAll()
  )
  .subscribe(console.log);

combineLatest

// before(deprecated)
import { of, combineLatest, asyncScheduler } from 'rxjs';

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

// after
import { of, scheduled, asyncScheduler } from 'rxjs';
import { combineAll } from 'rxjs/operators';

scheduled([of(1), of(2), of(3)], asyncScheduler)
  .pipe(
    combineAll()
  )
  .subscribe(console.log);

この記述は確かに等価だ。しかしもともとの動きとして、subscribeの実行がcombineLatest/combineAllするObservableの数+1回分、与えたSchedulerの時間で遅らされていることに注意を要する。

ハードにSchedulerを使い込んでいて非同期の実行タイミングに厳しい場合は、 scheduled を使わずに observeOn / subscribeOn を用いてemissionとsubscriptionのタイミングを操作してやる必要があるかもしれない。

Operators

startWith

// before(deprecated)
import { of, concat, asyncScheduler } from 'rxjs';
import { startWith } from 'rxjs/operators';

of(3)
  .pipe(
    startWith(1, 2, asyncScheduler)
  )
  .subscribe(console.log)

// after
import { of, scheduled, asyncScheduler } from 'rxjs';
import { concatAll } from 'rxjs/operators';

scheduled([[1, 2], of(3)], asyncScheduler)
  .pipe(
    concatAll()
  )
  .subscribe(console.log);

endWith

// before(deprecated)
import { of, concat, asyncScheduler } from 'rxjs';
import { endWith } from 'rxjs/operators';

of(1)
  .pipe(
    endWith(2, 3, asyncScheduler)
  )
  .subscribe(console.log)

// after
import { of, scheduled, asyncScheduler } from 'rxjs';
import { concatAll } from 'rxjs/operators';

from([of(1), scheduled([2, 3], asyncScheduler)])
  .pipe(
    concatAll()
  )
  .subscribe(console.log);

startWith endWith 共に正確に実行タイミングが等価になるような実装を示しているが、そこまで正確でなくてよい場合はうまくやってもらいたい。

v6でdeprecatedだった一部Operatorsの扱い変更

Creation FunctionsとOperatorsで同名の実装が存在した次のOperatorsは、リネームと差別化が図られる:

  • concat -> concatWith
  • merge -> mergeWith
  • zip -> zipWith
  • combineLatest -> combineLatestWith

リネームは上記の通りに -With を補った名前になる。差別化は後述する形の改善と、scheduler引数およびresultSelector引数(あれば)の先んじての削除が入る。

型の強化

これまで、Observableを引数に受け取るような関数の型は、長大なオーバーロード定義によって限られた数の引数にのみ適切なUnion型やTuple型を返していたが、これが任意個の引数に対して動作するようになる。

see. ReactiveX/rxjs#5254, ReactiveX/rxjs#5257

ex.

import { combineLatestWith } from 'rxjs/operators';

const a = of(1, 2, 3);
const b = of('a', 'b', 'c');
const c = of('d', 'e', 'f');
const d = of('g', 'h', 'i');
const e = of('j', 'k', 'l');
const f = of('m', 'n', 'o');
const g = of('p', 'q', 'r');
const res = a.pipe(combineLatestWith(b, c, d, e, f, g))

// before
res; // $ExpectType Observable<(string | number)[]>

// after
res; // $ExpectType Observable<[number, string, string, string, string, string, string]>

from ReactiveX/rxjs#5257

TestScheduler の変化

v6時点から特定のメソッドを用いることで使えた、 frameTimeFactormaxFrameCount に関する変化は継続しており、テストには run メソッドを用いておけば問題ない。

run に関しては以前記事を書いているので移譲する。 → https://qiita.com/berlysia/items/dad98488c4bdde938ef3

rxjs-compat の削除

v5からv6への移行に際して、Pipeable Operatorやインポートパス整理など大きな変化を吸収するためのモジュールが存在したが、v7を迎えるに当たって消える予定がある。

内容はドキュメントを見よ: https://github.com/ReactiveX/rxjs/blob/473a66813c841ee2763eac186d0ac47ea1737815/docs_app/content/guide/v6/migration.md#drop-compat

他、v6でのdeprecatedな実装の削除

ドキュメントを見よ: https://github.com/ReactiveX/rxjs/blob/473a66813c841ee2763eac186d0ac47ea1737815/docs_app/content/guide/v6/migration.md#deprecations

他、v7に向けて

まだ数多くのPRが出ており、議論も行われているようだが、一番大きな変更は今のところ scheduled の追加周りだろうと筆者は見ている。

型周りの改善もまだまだ控えている様子なので、ユーザー側として実装の変化はスケジューラー周りが主でありながら、総じての使い勝手はよくなるものと期待している。

参考資料

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away