RxJS 맵 연산자 (각도)에서 오류를 발생시키는 방법


93

조건에 따라 Observable의 연산자 에서 오류를 던지고 싶습니다 . 예를 들어 올바른 API 데이터가 수신되지 않은 경우. 다음 코드를 참조하십시오.

private userAuthenticate( email: string, password: string ) {
    return this.httpPost(`${this.baseApiUrl}/auth?format=json&provider=login`, {userName: email, password: password})
        .map( res => { 
            if ( res.bearerToken ) {
                return this.saveJwt(res.bearerToken); 
            } else {
                // THIS DOESN'T THROW ERROR --------------------
                return Observable.throw('Valid token not returned');
            }
        })
        .catch( err => Observable.throw(this.logError(err) )
        .finally( () => console.log("Authentication done.") );
}

기본적으로 코드에서 볼 수 있듯이 응답 (res 객체)에 'bearerToken'이 없으면 오류를 버리고 싶습니다. 그래서 내 구독에서 아래에 언급 된 두 번째 매개 변수 (handleError)로 이동합니다.

.subscribe(success, handleError)

어떤 제안?


4
어때 throw 'Valid token not returned';?
Günter Zöchbauer

컴파일 실패
Hassan

정확한 오류 메시지를 보내주세요.
Günter Zöchbauer

2
아 죄송합니다 . return throw 'message here'작동하지 않지만 return키워드 없이 작동 합니다. 논리적으로 올바르게 작동하는지 확인하겠습니다.
Hassan

오류 텍스트가 subscribe메서드 에서 수신되지 않고 .finally()스트림에서도 트리거됩니다. (그러나 실행이 중지되는 것은 좋은 일입니다)
Hassan

답변:


141

map()연산자 내부에 오류를 던지면 됩니다. RxJS의 모든 콜백은 try-catch 블록으로 래핑되어 있으므로 포착 된 다음 error알림으로 전송됩니다 .

이것은 아무것도 반환하지 않고 오류를 던지는 것을 의미합니다.

map(res => { 
  if (res.bearerToken) {
    return this.saveJwt(res.bearerToken); 
  } else {
    throw new Error('Valid token not returned');
  }
})

throwError()(구 Observable.throw()RxJS 5)을 그냥 보내는 있다는 관측 error통지를하지만 map()당신이 돌아하든 상관하지 않습니다. Observable을 반환하더라도 알림 map()으로 전달됩니다 next.

마지막으로, 아마도 사용할 필요가 없을 것입니다 .catchError()(이전 catch()RxJS 5). 오류가 발생했을 때 부작용을 수행해야하는 경우 예를 들어 RxJS 5의 tap(null, err => console.log(err))이전 버전 을 사용하는 것이 좋습니다 do().

2019 년 1 월 : RxJS 6 업데이트


1
감사합니다 @martin-네 솔루션이 작동합니다. 실제로 @ GünterZöchbauer가 지적한 logError 메서드 내부에도 문제가있었습니다. 나는 return그것으로부터 오류 객체를 가지고 있었고 이제 완벽하게 작동합니다 :) 감사합니다!
Hassan

@martin : 왜 우리가 .catch ()를 원하지 않는지 개발해 주시겠습니까?
Bob

1
@Bob OP는 catch()오류를 기록하고 다시 던지는 데만 사용했기 때문에 부작용 (오류 기록)을 수행하려는 경우에는 불필요하고 사용하기가 더 쉽습니다do()
martin

1
이것과 동일 return throwError(new Error('Valid token not returned'));합니까?
Simon_Weaver

@Simon_Weaver 아니에요. return throwError()를 반환합니다 Observable<never>. 이것은 전혀 반환하지 않고 관찰 가능한 스트림을 즉시 중단합니다.
Monica 복원

25

throw new Error()관찰 할 수없는 것처럼 느껴진다면 대신 throwError(...)with switchMap를 사용할 수 있습니다 map(차이가 switchMap새로운 관찰 가능 항목을 반환 함).

// this is the import needed for throwError()
import { throwError } from 'rxjs';


// RxJS 6+ syntax
this.httpPost.pipe(switchMap(res => { 
   if (res.bearerToken) {
      return of(this.saveJwt(res.bearerToken)); 
   } 
   else {
      return throwError('Valid token not returned');  // this is 
   }
});

또는 더 간결하게 :

this.httpPost.pipe(switchMap(res => (res.bearerToken) ? 
                                    of(this.saveJwt(res.bearerToken)) : 
                                    throwError('Valid token not returned')
));

동작은 동일하며 구문이 다릅니다.

당신은 말 그대로 파이프에서 관찰 가능한 http에서 다른 관찰 가능한 것으로 '전환'이라고 말하고 있는데, 이는 출력 값을 '래핑'하거나 새로운 '오류'관찰 가능한 것입니다.

입력하는 것을 잊지 마십시오. 그렇지 않으면 of혼란스러운 오류 메시지가 표시됩니다.

또한 'switchMap'의 장점은 .NET을 사용하여 수행해야하는 논리에 대해 원하는 경우 완전히 새로운 '체인'명령을 반환 할 수 있다는 것입니다 saveJwt.


4
switchMap비동기식 if문 으로 생각하기 시작하면 일이 훨씬 더 의미가 있습니다. :-)
Simon_Weaver

3

이 질문에 대한 답변은 이미 있지만 저의 접근 방식을 공유하고 싶습니다 (위와 약간만 다를지라도).

매핑과 별도로 반환되는 항목을 결정하고 그 반대의 경우도 마찬가지입니다. 어떤 연산자가 가장 적합한 지 잘 모르겠으므로 tap.

this.httpPost.pipe(
  tap(res => { 
    if (!res.bearerToken) {
      throw new Error('Valid token not returned');
    }
  }),
  map(res => this.saveJwt(res.bearerToken)),
);

의 반환 값 tap은 무시됩니다. 그것이 말하는 것보다이 코드는 다른 일을
김포

나는 여전히 rxjs에 익숙해지고 있습니다. switchMap을 사용하는 것이 더 좋을까요? 누군가 다른 연산자를 제안하거나 직접 편집 할 수 있습니까?
christo8989

throw new Error()지금까지 제안 된 것이 최선의 선택 이라고 생각합니다
sf
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.