У меня довольно сложное реактивное поведение, которого я хотел бы добиться с помощью RxJS, но пока не нашел подходящего решения.
В моем приложении angular, которое можно найти в Plnkr, у меня есть серия синхронного, асинхронного и параллельного асинхронного выполнения.
Сначала пользователь нажимает кнопку, которая вызывает следующий мой RxJS Subject.
userClick$ = new Subject<void>();.
<button (click) = "model.on = !model.on; userClick$.next()">
{{ model.on ? 'Stop' : 'Start' }}
</button>
getRandomNumbergetExpNumbergetFloor и getCeil параллельно.forkJoin в последних двух параллельных выполнениях # 4.flatMap, в настоящее время я получаю только последнее значение (мне нужно отобразить случайное значение (первое flatMap) пользователю, используя канал ngFor и async.Зависимость: я могу добиться этого, проверяя тип моего текущего наблюдаемого значения в каждом flatMap, но я думаю, что должен быть лучший способ.
Полный код:
import { Component, NgModule, VERSION } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/switchMap';
@Component({
selector: 'my-app',
template: `
<button (click) = "model.on = !model.on; userClick$.next()">{{ model.on ? 'Stop' : 'Start' }}</button>
<h1>Numbers stream</h1>
<div *ngFor = "let numberValue of (numbers$ | async)">
<h2>{{ numberValue }}</h2>
</div>
<label>{{ model.log }}</label>
`,
})
export class App {
model = {
on: false,
log: ''
}
userClick$ = new Subject<void>();
numbers$: Observable<number[]> = this.userClick$
.filter(() => !!this.model.on)
.do(() => this.model.log = '')
.switchMap(() => this.getRandomNumber())
.switchMap((num) => this.getExpNumber(num))
.switchMap((num) => this.getFloor(num))
.switchMap((num) => this.getCeil(num));
constructor() {
}
/**
* Runs after user click
*/
getRandomNumber(): Observable<number[]> {
return new Observable<number[]>(observer => {
this.model.log += ' getRandomNumber';
observer.next([Math.floor(Math.random() * 10) + 1]);
return () => {}
}
}
/**
* Depends on getRandomNumber and run after it
*/
getExpNumber(n: number): Observable<number[]> {
return new Observable<number[]>(observer => {
this.model.log += ' getExpNumber';
observer.next([Math.floor(Math.exp(n)]);
return () => {}
}
}
/**
* Runs in parallel with getCeil
*/
getFloor(n: number): Observable<number[]> {
return new Observable<number[]>(observer => {
this.model.log += ' getFloor';
observer.next([Math.floor(n)]);
return () => {}
}
}
/**
* Runs in parallel with getFloor
*/
getCeil(n: number): Observable<number[]> {
return new Observable<number[]>(observer => {
this.model.log += ' getCeil';
observer.next([Math.ceil(n)]);
return () => {}
}
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}





для меня странно, как вы создаете наблюдаемые (я буду использовать "of"), и я получил число, а не массив, поэтому код похож на
@Component({
selector: 'my-app',
template: `
<button (click) = "model.on = !model.on; userClick$.next()">{{ model.on ? 'Stop' : 'Start' }}</button>
<h1>Numbers stream</h1>
<h2 *ngFor = "let numberValue of (numbers$ |async)">{{numberValue}}</h2>
<label>{{ model.log }}</label>
`,
})
export class HomeComponent {
model = {
on: false,
log: ''
}
userClick$ = new Subject<void>();
numbers$: Observable<number[]> = this.userClick$
.switchMap(() => {
return this.getRandomNumber().switchMap((num: number) => {
this.model.log += num;
return this.getExpNumber(num).switchMap((num2: number) => {
this.model.log += num2;
return forkJoin(this.getFloor(num2), this.getCeil(num2))
})
})
})
getRandomNumber(): Observable<number> {
this.model.log += ' getRandomNumber';
return of((Math.random() * 10) + 1);
}
getExpNumber(n: number): Observable<number> {
this.model.log += ' getExpNumber';
return of(Math.exp(n));
}
getFloor(n: number): Observable<number> {
this.model.log += ' getFloor';
return of((Math.floor(n)));
}
getCeil(n: number): Observable<number> {
this.model.log += ' getCeil';
return of(Math.ceil(n));
}
}
Если вы хотите только getRandomNumber, вы можете подписаться только на getRandomNumber.
this.getRandomNumber().subscribe((value:number)=>{console.info(value)})
ПРИМЕЧАНИЕ: когда мы пишем
<div *ngFor = "let value of ($numbers |async)>{{value}}</div>
Как"
//in .html
<div *ngFor = "let value of numberList>{{value}}</div>
//in .ts
numberList:number[]
subscription:Subscription;
ngOnInit()
{
this.subscription=$numbers.subscribe(values:number[]=>{
this.numberList=values;
this.subscription.unsubscribe()
}
}
Интересное решение, позволяющее использовать forkJoin Спасибо @Eliseo. Теперь мне нужно найти чистый способ вернуть только значение из
getRandomNumberв мой потокnumbers$.