この記事は現時点で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時点から特定のメソッドを用いることで使えた、 frameTimeFactor
と maxFrameCount
に関する変化は継続しており、テストには run
メソッドを用いておけば問題ない。
run
に関しては以前記事を書いているので移譲する。 → https://qiita.com/berlysia/items/dad98488c4bdde938ef3
rxjs-compat
の削除
v5からv6への移行に際して、Pipeable Operatorやインポートパス整理など大きな変化を吸収するためのモジュールが存在したが、v7を迎えるに当たって消える予定がある。
他、v6でのdeprecatedな実装の削除
他、v7に向けて
まだ数多くのPRが出ており、議論も行われているようだが、一番大きな変更は今のところ scheduled
の追加周りだろうと筆者は見ている。
型周りの改善もまだまだ控えている様子なので、ユーザー側として実装の変化はスケジューラー周りが主でありながら、総じての使い勝手はよくなるものと期待している。