web-dev-qa-db-ja.com

RxJSを使ったAngular 2 - take(1)vs first()

私はtake(1)を使うAuth Guardの実装をほとんど見つけませんでした。私のプロジェクトでは、自分のニーズを満たすためにfirst()を使用しました。それは同じように機能しますか?あるいは、そのうちの1つに利点があるかもしれません。

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/first';
import { Observable } from 'rxjs/Observable';

import { Injectable } from '@angular/core';
import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AngularFire } from 'angularfire2';

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private angularFire: AngularFire, private router: Router) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
        return this.angularFire.auth.map(
            (auth) =>  {
                if (auth) {
                    this.router.navigate(['/dashboard']);
                    return false;
                } else {
                    return true;
                }
            }
        ).first(); // Just change this to .take(1)
    }
}
66
Karuban

演算子first()take()は同じではありません。

first()演算子は、オプションのpredicate関数を取り、ソースが完了したときに値が一致しなかった場合にerror通知を発行します。

例えばこれはエラーを出すでしょう:

import { EMPTY, range } from 'rxjs';
import { first, take } from 'rxjs/operators';

EMPTY.pipe(
  first(),
).subscribe(console.log, err => console.log('Error', err));

... これと同様に:

range(1, 5).pipe(
  first(val => val > 6),
).subscribe(console.log, err => console.log('Error', err));

これは最初に発行された値と一致しますが:

range(1, 5).pipe(
  first(),
).subscribe(console.log, err => console.log('Error', err));

一方、take(1)は最初の値を取り、完了します。それ以上の論理は含まれていません。

range(1, 5).pipe(
  take(1),
).subscribe(console.log, err => console.log('Error', err));

それから空のソースObservableを使ってもエラーにはなりません。

EMPTY.pipe(
  take(1),
).subscribe(console.log, err => console.log('Error', err));

2019年1月:RxJS 6用に更新

105
martin

ヒント:以下の場合にのみfirst()を使用してください。

  • 発行されたアイテムがゼロであることをエラー条件と見なします(例:発行前に完了する) AND エラーが0%を超える可能性がある場合は問題なく処理できます
  • またはソースの観測量から1 +の項目が放出されることが100%わかっているので(決してスローされることはありません)

ゼロエミッションがあり、明示的に処理していない場合(catchErrorを使用)、そのエラーが発生する可能性があります。予期しない問題が発生する可能性があります。

あなたは安全 offであれば、ほとんどの部分でtake(1)を使用しています。

  • ソースが発行されずに完了した場合、take(1)は何も発行しません。
  • インライン述語を使う必要はありません(例:first(x => x > 10)

注:あなたはtake(1)の述語を使うことができます:.pipe( filter(x => x > 10), take(1) )。何も10よりも大きいものがなければ、これによるエラーはありません。

single()はどうですか

さらに厳密になり、2つの排出量を許可したくない場合は、single()を使用できます。ゼロまたは2+排出量の場合はエラーになります。その場合も、エラーを処理する必要があります。

ヒント:Singleは、オブザーバブルチェーンでhttpサービスを2回呼び出して2つのオブザーバブルを発行するなどの特別な作業を行わないようにしたい場合に便利なことがあります。パイプの最後にsingleを追加すると、そのような間違いを犯したかどうかがわかります。 1つの値しか発行しないタスクオブザーバブルを渡すタスクランナーでこれを使用しています。そのため、single(), catchError()を介して応答を渡し、適切な動作を保証します。


なぜfirst()の代わりにtake(1)を使わないのですか?

別名。どのようにfirstが潜在的により多くのエラーを引き起こす可能性がありますか?

サービスから何かを取り出してfirst()を通してパイプライン処理するオブザーバブルがある場合は、ほとんどの場合大丈夫です。しかし、なんらかの理由で誰かがサービスを無効にして、of(null)またはNEVERを発行するように変更した場合、下流のfirst()演算子はエラーをスローし始めます。

今私はそれがあなたが望むものであることができる - それ故にこれが単なるヒントである理由であるかもしれないことに気づきます。演算子firsttake(1)よりも少し不器用に聞こえたため、私に訴えましたが、ソースが出力されない可能性がある場合はエラーの取り扱いに注意する必要があります。完全にあなたがやっていることに依存します。


デフォルト値(定数)がある場合:

何も出力されない場合に使用すべきデフォルト値がある場合は.pipe(defaultIfEmpty(42), first())も検討してください。 firstは常に値を受け取るので、これはもちろんエラーにはなりません。

defaultIfEmptyは、ストリームが空の場合にのみトリガされ、発行されるものの値がnullの場合にはトリガされません。

9
Simon_Weaver

RxJS 5.2.0では.first()演算子に バグ があるようです。

その.take(1).first()switchMapと一緒に使用している場合は、その動作がかなり異なる可能性があります。

take(1)を使用すると、期待通りの動作になります。

var x = Rx.Observable.interval(1000)
   .do( x=> console.log("One"))
   .take(1)
   .switchMap(x => Rx.Observable.interval(1000))
   .do( x=> console.log("Two"))
   .subscribe((x) => {})

// In the console you will see:
// One
// Two
// Two
// Two
// Two
// etc...

しかし.first()を使うと間違った振る舞いをするでしょう:

var x = Rx.Observable.interval(1000)
  .do( x=> console.log("One"))
  .first()
  .switchMap(x => Rx.Observable.interval(1000))
  .do( x=> console.log("Two"))
  .subscribe((x) => {})

// In console you will see:
// One
// One
// Two
// One
// Two
// One
// etc... 

これは codepen へのリンクです。

9
Artem

どこにも述べられていない1つの本当に重要な違いがあります。

take(1)は1を発行し、完了し、購読を中止します。

first()は1を発行して完了しますが、購読解除はしません。

それはあなたの上流の観測可能性がfirst()の後にまだ熱いであろうことを意味します。

UPD:これはRxJS 5.2.0を参照しています。この問題はすでに修正されている可能性があります。

8
norekhov

以下は、AB、およびCの演算子の違いを調べるための、3つのオブザーバブルfirsttake、およびsingleで、大理石のダイアグラムを持つものです。

first vs take vs single operators comparison

*凡例
--o--
----!エラー
----|補完

https://thinkrx.io/rxjs/first-vs-take-vs-single/で再生してください。

すでにすべての答えを得ているので、もっと視覚的な説明を加えたい

誰かに役立つことを願っています

3
kos