カテゴリー
【Rxjs基礎講座】GeneratorをObservableへ変換する方法
※ 当ページには【広告/PR】を含む場合があります。
2020/07/17
2022/10/05
async/await
generator
Generatorの簡単なおさらい
javascript generator
async/await
Generator<T>
function* generator(): Generator<any> {
yield 0;
let i = 4;
yield 1;
yield 'HOGE';
yield 2 + i;
i++;
yield 'PIYO';
yield 1.0e-3 * i;
yield false;
yield 'FUGA';
yield i - 3;
yield true;
}
const iterator = generator();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
$ node dist/index.js
{ value: 0, done: false }
{ value: 1, done: false }
{ value: 'HOGE', done: false }
{ value: 6, done: false }
{ value: 'PIYO', done: false }
{ value: 0.005, done: false }
{ value: false, done: false }
{ value: 'FUGA', done: false }
{ value: 2, done: false }
{ value: true, done: false }
{ value: undefined, done: true }
{ value: undefined, done: true } # 処理が終わってもGeneratorは消滅せずに残る
yield
next()
{value: any, done: boolean}
value
done
GeneratorからObservableへの変換
検証① ~ fromオペレーターから
fromオペレーター
import { Observable, from } from 'rxjs';
import { take } from 'rxjs/operators';
function* generator(): Generator<any> {
yield 0;
let i = 4;
yield 1;
yield 'HOGE';
yield 2 + i;
i++;
yield 'PIYO';
yield 1.0e-3 * i;
yield false;
yield 'FUGA';
yield i - 3;
yield true;
}
// 👇fromオペレーターからジェネレーターもObservableへ一発変換
const iterator$ = from(generator()).pipe(
take(11)
);
iterator$.subscribe(
res => console.log(res),
err => console.log(err),
() => console.log('DONE!')
);
$ node dist/index.js
0
1
HOGE
6
PIYO
0.005
false
FUGA
2
true
DONE! # Generatorの処理が終わったらtakeでUnsubscribe
value
next()
done
true
complete()
検証② ~ deferオペレーターから
defer
import { Observable, defer } from 'rxjs';
import { take } from 'rxjs/operators';
function* generator(): Generator<any> {
yield 0;
let i = 4;
yield 1;
yield 'HOGE';
yield 2 + i;
i++;
yield 'PIYO';
yield 1.0e-3 * i;
yield false;
yield 'FUGA';
yield i - 3;
yield true;
}
// 👇deferオペレーターからジェネレーターもObservableへ一発変換
const iterator$ = defer(generator).pipe(
take(11)
);
iterator$.subscribe(
res => console.log(res),
err => console.log(err),
() => console.log('DONE!')
);
Generator<any>
ジェネレーター関数
応用編 ~ mergeMap(flatMap)のresultSelector(第二引数)を理解する
resultSelector
resultSelector
Projects each source value to an Observable which is merged in the output Observable.
mergeMap<T, R, O extends ObservableInput<any>>(
project: (value: T, index: number) => O,
resultSelector?: number |
((outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number) => R),
concurrent: number = Number.POSITIVE_INFINITY
): OperatorFunction<T, ObservedValueOf<O> | R>
Parameters:
project:
A function that, when applied to an item emitted by the source Observable,
returns an Observable.
resultSelector:
Optional. Default is undefined.
Type:
number |
((outerValue: T, innerValue: ObservedValueOf, outerIndex: number, innerIndex: number) => R).
concurrent:
Optional.
Default is Number.POSITIVE_INFINITY.
Maximum number of input Observables being subscribed to concurrently.
Returns:
OperatorFunction<T, ObservedValueOf<O> | R>:
An Observable that emits the result of applying the projection function
(and the optional deprecated resultSelector) to each item emitted
by the source Observable and merging the results of the Observables
obtained from this transformation.
mergeMap
resultSelector
resultSelector
import { Observable, of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
function genWithMergemap$(): Observable<any> {
return of(1,5,8).pipe(
mergeMap(
(x: any, i: number) => (function* () {
yield x;
yield i;
})(),
// (outerValue: T, innerValue: ObservedValueOf, outerIndex: number, innerIndex: number)
// (outerValue) oV: 1 --> 5 --> 8 (member in array of "of")
// (innerValue) iV: return a member in array as the the generator has observed.
// (outerIndex) oI: 0 --> 1 --> 2 (index of member in the array in "of").
// (innerIndex) iI: 0 --> 1 (index that the generator rolls inside).
(oV: any, iV: any, oI: number, iI: number) => {
return `oV: ${oV}, iV: ${iV}, oI: ${oI}, iI: ${iI}`;
}
)
);
}
const source = genWithMergemap$();
source.subscribe(
x => console.log('Next: | %s |', x),
e => console.log('Error: %s', e),
() => console.log('Completed')
);
$ node dist/index.js
Next: | oV: 1, iV: 1, oI: 0, iI: 0 |
Next: | oV: 1, iV: 0, oI: 0, iI: 1 |
Next: | oV: 5, iV: 5, oI: 1, iI: 0 |
Next: | oV: 5, iV: 1, oI: 1, iI: 1 |
Next: | oV: 8, iV: 8, oI: 2, iI: 0 |
Next: | oV: 8, iV: 2, oI: 2, iI: 1 |
Completed
resultSelector
https://rxjs-dev.firebaseapp.com/api/operators/mergeMap
「1 --> 3 --> 5 --> ...」
「10 --> 10 --> 10 --> ...」
「1 --> 3 --> 5 --> ...」
「10 --> 10 --> 10 --> ...」
of
「1 --> 5 --> 8 --> ...」
yeild
Innerストリーム
project
(value: T, index: number) => O
O
//....
(x: any, i: number) => (function* () {
yield x;
yield i;
})()
//...
yield
project
Innerストリーム
Outerストリーム
of(1,5,8)
resultSelectorのマトリックス表記
(outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number)
outerValue
1,5,8
outerIndex
innerValue
innerIndex
yield
yield x;
0
yield i;
1
innerValue
yield
yield
x
i
outerValue
Eq. (1)
innerValue
Eq. (2)
innerIndex
0
yield x;
1
yield i;
まとめ
resultSelector
project
参考サイト
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー