Угловое 2 с использованием RxJS – принять (1) против первого ()

Я нашел несколько реализаций Auth Guard, которые используют take(1) . В моем проекте я использовал first() для удовлетворения моих потребностей. Это работает так же? Или один из них может иметь преимущества или около того.

 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 { 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 когда значение не сравнивается, когда источник завершен.

    Например, это приведет к ошибке:

     Rx.Observable.empty() .first() .subscribe(console.log, err => console.log('Error', err)); 

    … а также это:

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

    Хотя это будет соответствовать первому вычисленному значению:

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

    С другой стороны, take(1) просто берет первое значение и завершает. Никакой дополнительной логики не задействовано.

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

    Затем с пустым источником Observable он не выдаст никакой ошибки:

     Rx.Observable.empty() .take(1) .subscribe(console.log, err => console.log('Error', err)); 

    Похоже, что в RxJS 5.2.0 .first () оператор имеет ошибку ,

    Из-за этой ошибки .take (1) и .first () могут вести себя совсем по-другому, если вы используете их с картой переключения:

    С 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 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

    Есть одно действительно важное различие, которое нигде не упоминается.

    take (1) испускает 1, завершает, отписывает

    first () испускает 1, завершает, но не отписывает.

    Это означает, что ваш восходящий наблюдаемый будет по-прежнему горячим после первого (), который, вероятно, не ожидается.

    UPD: Это относится к RxJS 5.2.0. Эта проблема может быть исправлена.

    Давайте будем гением компьютера.