[angular] take (1) vs first ()

나는 몇 가지 구현을 발견했다. AuthGuard을 사용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> | 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(1)동일하지 않습니다.

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()경우 에만 사용 하십시오.

  • 당신은 제로 항목은 오류 상태로 방출 (예. 발광하기 전에 완료) 고려 AND 오류의 큰 0 % 이상 기회가 있다면 당신은 정상적으로 그것을 처리
  • 또는 100 %는 관측 가능한 소스가 1 개 이상의 아이템을 방출한다는 것을 알고 있습니다 .

배출량이 0이고 명시 적으로 처리하지 않으면 (으로 catchError) 해당 오류가 전파되어 다른 곳에서 예기치 않은 문제가 발생할 수 있으며 특히 최종 사용자가 올 경우 추적이 까다로울 수 있습니다.

다음 과 같은 경우 대부분 사용 하는 것이 안전take(1) 합니다.

  • 당신은 괜찮습니다 take(1) 소스가 방출없이 완료하면 아무것도 방출하지.
  • 당신은 인라인 술어를 사용할 필요가 없습니다 (예. first(x => x > 10))

참고 : 다음 과 같은 조건자를 사용할 수 있습니다take(1) ..pipe( filter(x => x > 10), take(1) ) . 10보다 큰 것이 없으면 오류가 없습니다.

이건 어떤가요 single()

더 엄격하고 두 가지 배출을 허용하지 않으려면 배출 single()0 또는 2 이상인 경우 어떤 오류를 사용할 수 있습니다 . 이 경우에도 오류를 처리해야합니다.

팁 : Single옵저버 블 체인이 http 서비스를 두 번 호출하고 두 개의 옵저버 블을 방출하는 등의 추가 작업을 수행하지 않도록하려면 때때로 유용 할 수 있습니다. single파이프 끝에 추가 하면 실수를 저지른 경우 알려줍니다. 하나의 값만 방출 해야하는 관찰 가능한 작업을 전달하는 ‘태스크 러너’에서 사용하고 있으므로 single(), catchError()좋은 동작을 보장하기 위해 응답을 전달합니다 .


왜 항상 first()대신에 사용 하지 않는가?take(1) 않습니까?

일명. 어떻게 first 잠재적으로 으로 더 많은 오류가 발생할 무엇입니까?

서비스에서 무언가를 가져 와서 파이프를 통해 관찰 할 수있는 관찰 가능 항목이 있다면 first()대부분의 시간에 문제가 없을 것입니다. 그러나 누군가가 어떤 이유로 든 서비스를 비활성화하기 위해 온다면-서비스를 방출 of(null)하거나 NEVER다운 스트림으로 변경하면first() 연산자는 오류를 던지기 시작합니다.

이제는 이것이 정확히 당신이 원하는 것일 수 있다는 것을 알고 있습니다 . 운영자 first는 ‘서투른’소리보다 약간 덜 들었 기 때문에 나에게 호소 take(1)했지만 소스가 방출되지 않을 가능성이있는 경우 오류 처리에주의해야합니다. 당신이하고있는 일에 전적으로 달려 있습니다.


기본값이있는 경우 (일정한) :

.pipe(defaultIfEmpty(42), first())아무 것도 방출되지 않으면 사용해야하는 기본값이 있는지도 고려하십시오 . 이것은 물론 오류를 일으키지 않습니다.first 항상 값을 받기 .

defaultIfEmpty에만 스트림이 비어있는 경우 트리거가 방출되는 것의 값이없는 경우 null.


답변

여기에 세 가지 Observables은있다 A, B그리고 C대리석 다이어그램의 차이를 탐구 first, take그리고 single운영자는 :

첫 대 대 연산자 비교

* 범례 :
--o--
----! 오류
----| 완료

https://thinkrx.io/rxjs/first-vs-take-vs-single/ 에서 함께 플레이 하십시오 .

이미 모든 답을 가지고 더 시각적 인 설명을 추가하고 싶었습니다.

누군가에게 도움이되기를 바랍니다.


답변

어디에도 언급되지 않은 한 가지 중요한 차이점이 있습니다.

take (1)은 1을 방출하고 완료하고 구독을 취소합니다.

first ()는 1을 내고 완료하지만 구독 취소하지 않습니다.

이는 업스트림 관측 가능 항목이 first () 이후에도 여전히 뜨거워 예상되는 동작이 아님을 의미합니다.

UPD : RxJS 5.2.0을 나타냅니다. 이 문제는 이미 해결되었을 수 있습니다.


답변

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에 대한 링크입니다


답변