使用没有副作用的rxjs显示飞行中请求指标的最佳方法是什么?

时间:2018-05-30 14:35:42

标签: angular rxjs

使用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%确定性,无副作用

缺点: 必须介绍另一个主题

1 个答案:

答案 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效果的方法。然后你只需根据你想要的东西进行过滤。如果您有多个订阅(您可能会这样),则必须共享。这是一个例子。

&#13;
&#13;
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;
&#13;
&#13;

或者您可以将触发器与结果合并,并将每个触发器映射到加载状态。您必须静音并返回错误的内容。

&#13;
&#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;
&#13;
&#13;