私は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)
}
}
演算子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用に更新
first()
を使用してください。ゼロエミッションがあり、明示的に処理していない場合(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()
演算子はエラーをスローし始めます。
今私はそれがあなたが望むものであることができる - それ故にこれが単なるヒントである理由であるかもしれないことに気づきます。演算子first
はtake(1)
よりも少し不器用に聞こえたため、私に訴えましたが、ソースが出力されない可能性がある場合はエラーの取り扱いに注意する必要があります。完全にあなたがやっていることに依存します。
何も出力されない場合に使用すべきデフォルト値がある場合は.pipe(defaultIfEmpty(42), first())
も検討してください。 first
は常に値を受け取るので、これはもちろんエラーにはなりません。
defaultIfEmpty
は、ストリームが空の場合にのみトリガされ、発行されるものの値がnull
の場合にはトリガされません。
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 へのリンクです。
どこにも述べられていない1つの本当に重要な違いがあります。
take(1)は1を発行し、完了し、購読を中止します。
first()は1を発行して完了しますが、購読解除はしません。
それはあなたの上流の観測可能性がfirst()の後にまだ熱いであろうことを意味します。
UPD:これはRxJS 5.2.0を参照しています。この問題はすでに修正されている可能性があります。
以下は、A
、B
、およびC
の演算子の違いを調べるための、3つのオブザーバブルfirst
、take
、およびsingle
で、大理石のダイアグラムを持つものです。
*凡例:--o--
値----!
エラー----|
補完
https://thinkrx.io/rxjs/first-vs-take-vs-single/で再生してください。
すでにすべての答えを得ているので、もっと視覚的な説明を加えたい
誰かに役立つことを願っています