使用RXJS(和Angular2 +)显示飞行请求的加载指示器而不在管道()函数中引入副作用的首选方法是什么?
以下是我提出的选项。是否有一个特殊推荐或更好的选择?
选项1:通过do();
使用副作用results$ = userEvent$.pipe(do(()=> { this.loading = true; }), switchMap(()=> service.externalCall()), do(()=> { this.loading = false; }))
优点:最简单 缺点:除非使用' share'。
,否则可能会遇到多个订阅者的边缘情况选项2:添加单独的订阅以设置加载指标
userEvent$.subscribe(()=> {this.loading = true;} )
const results$ = userEvent$.pipe(switchMap(()=> service.externalCall()))
// Is this always guarenteed to fire after the first statement?
results$.subscribe(() => {this.loading = false;});
优点: pipe()运算符中没有副作用
缺点: 更多的观察者漂浮在周围 不清楚订单是否具有确定性。
选项3:创建新主题
const subject = new Subject();
userEvent$.subscribe(()=> { this.loading = true; subject.next(); } )
const result$ = subject.asObservable().pipe(switchMap(() => service.externalCall()));
result$.subscribe(() => { this.loading = false; });
优点: 100%确定性,无副作用
缺点: 必须介绍另一个主题
答案 0 :(得分:1)
我个人使用副作用(<?php
use Illuminate\Database\Seeder;
class PaymentTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$json = File::get('database/data/payment-gateway.json');
$data = json_decode($json, true);
foreach($data as $obj){
DB::table('payment_settings')->insert([
'identity' => $obj->identity,
'config' => $obj->config,
'status' => $obj->status
]);
}
}
}
)因为它更简单。
您可以使用将所有消息建模为事件的方法。因此,在同一个管道上发生的事件可能是“加载”,“成功”,“失败”等等。我已经看到了这种具有ngrx效果的方法。然后你只需根据你想要的东西进行过滤。如果您有多个订阅(您可能会这样),则必须共享。这是一个例子。
do/tap
&#13;
console.clear();
const { interval, of, throwError: _throw } = rxjs;
const { switchMap, take, delay, map, startWith, catchError, share } = rxjs.operators;
let callCount = 0;
function fakeApiCall() {
callCount++;
let response = callCount === 3
? _throw(new Error(callCount))
: of(callCount);
return response.pipe(delay(Math.random() * 1000));
}
const EventType = {
Loading: 'Loading',
Success: 'Success',
Failure: 'Failure'
};
const trigger = interval(1000).pipe(take(5));
const stream = trigger.pipe(
switchMap(() => {
return fakeApiCall().pipe(
map((x) => ({ type: EventType.Success, payload: x })),
catchError((e) => of({ type: EventType.Failure, payload: e.message })),
startWith({ type: EventType.Loading })
);
}),
share()
);
const isLoading = stream.pipe(
map((x) => x.type === EventType.Loading)
);
stream.subscribe(
(x) => { console.log('stream', x); }
);
isLoading.subscribe(
(x) => { console.log('isLoading', x); }
);
&#13;
或者您可以将触发器与结果合并,并将每个触发器映射到加载状态。您必须静音并返回错误的内容。
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.1.0/rxjs.umd.js"></script>
&#13;
console.clear();
const { interval, merge, of, throwError: _throw } = rxjs;
const { delay, take, switchMap, share, catchError, mapTo, distinctUntilChanged } = rxjs.operators;
let callCount = 0;
function fakeApiCall() {
callCount++;
let response = callCount === 2
? _throw(new Error(callCount))
: of(callCount);
return response.pipe(delay(Math.random() * 1000));
}
const trigger = interval(1000).pipe(take(5));
const stream = trigger.pipe(
switchMap(() => fakeApiCall().pipe(catchError((e) => of('err')))),
share()
);
const isLoading = merge(
trigger.pipe(mapTo(true)),
stream.pipe(mapTo(false))
).pipe(
distinctUntilChanged()
);
isLoading.subscribe(
(x) => { console.log('isLoading', x); }
);
stream.subscribe(
(x) => { console.log('stream next', x); }
);
&#13;