2017-02-20 29 views
20

Я нашел несколько реализаций Auth Guard, в которых используется take(1). В моем проекте я использовал first() для удовлетворения моих потребностей. Это работает так же? Или один из них может иметь преимущества или около того.Угловой 2 с использованием RxJS - take (1) vs 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> | 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) 
    } 
} 

ответ

36

Операторы first() и take() не то же самое.

first() оператор принимает необязательную predicate функцию и выдает error уведомления, когда значение не соответствует, когда источник завершен.

Например, это будет излучать ошибку:

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

..., а также следующим образом:

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

В то время как это будет соответствовать первое значение, излучаемого:

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

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

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

Затем с пустым источником Наблюдаемые не будет излучать какую-либо ошибку:

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

Так же, как примечание, я не сказал, что 'первый()' и 'взять()' одни и те же в общем, я думаю, это очевидно, только что 'первая()' и 'take (1)' совпадают. Я не уверен в вашем ответе, если вы считаете, что все еще есть разница? –

+3

@ GünterZöchbauer На самом деле, их поведение отличается. Если источник ничего не испускает и не завершает, тогда 'first()' посылает уведомление об ошибке, а 'take (1)' просто ничего не испустит. – martin

+0

Хорошо, теперь я понимаю.Большое спасибо :) –

3

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

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

первого() испускает 1, завершается, но не отказаться от подписки.

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

+0

Я не думаю, что кто-либо отменил подписку, см. Http://jsbin.com/nuzulorota/1/edit?js,console. – weltschmerz

+5

Да, оба оператора завершают подписку, разница в обработке ошибок. Если это наблюдаемое не испускает значения и все еще пытается взять первое значение, используя первый оператор, он выдает ошибку. Если мы заменим его на оператор take (1), даже если в потоке нет значения, когда происходит подписка, это не вызывает ошибку. – noelyahan

4

Похоже, что в RxJS 5.2.0 .Первый() оператор имеет bug,

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

с взятием (1) вы получите behviour, как и ожидалось:

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

Но с .Первый() вы получите неправильное поведение:

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

 Смежные вопросы

  • Нет связанных вопросов^_^