.then (성공, 실패)은 언제 약속의 반 패턴으로 간주됩니까?


188

나는 한 번 봐했다 블루 버드 약속 자주 묻는 질문 은 그 언급하는, .then(success, fail)안티 패턴입니다 . 시도와 캐치에 대한 설명을 이해하지 못합니다. 다음과 관련하여 무엇이 문제입니까?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

예제는 다음을 올바른 방법으로 제안하는 것 같습니다.

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

차이점이 뭐야?


1
then().catch()쉼표를 찾을 필요가없고 성공 또는 실패 분기에 대한이 콜백을 조사 할 필요가 없으므로 더 읽기 쉽습니다.
Krzysztof Safjanowski

7
@KevinB : 많은 차이가 있습니다. 답을 확인하십시오
Bergi

12
@KrzysztofSafjanowski- '더 좋아 보인다'라는 주장에 의해 황폐화되었습니다. 완전히 틀렸다!
Andrey Popov

6
참고 :을 사용할 때는 .catch마지막 단계 then또는 약속 체인의 어느 단계에서 문제의 원인이되었는지 알 수 없습니다 . 따라서 자체 단점이 있습니다.
vitaly-t

2
나는 항상 .then () 매개 변수에 함수 이름을 추가하여 읽을 수 있도록합니다.some_promise_call() .then(function fulfilled(res) { logger.log(res) }, function rejected(err) { logger.log(err) })
Shane Rowatt

답변:


215

차이점이 뭐야?

.then()호출은 콜백에서 오류가 발생하는 경우에 거부됩니다 약속을 반환합니다. 즉, 성공에 logger실패하면 오류가 다음 .catch()콜백 으로 전달 fail되지만와 함께 발생 하는 콜백 에는 전달 되지 않습니다 success.

제어 흐름도 는 다음과 같습니다 .

두 개의 인수로 제어 흐름 다이어그램 캐치 체인의 제어 흐름도

동기 코드로 표시하려면 다음을 수행하십시오.

// some_promise_call().then(logger.log, logger.log)
then: {
    try {
        var results = some_call();
    } catch(e) {
        logger.log(e);
        break then;
    } // else
        logger.log(results);
}

두 번째 log(첫 번째 인수와 같음 .then())는 예외가 발생하지 않은 경우에만 실행됩니다. 레이블이 붙은 블록과 break문장은 약간 이상하게 느껴집니다. 실제로 파이썬이 가지고있는 것 try-except-else입니다 (권장 독서!).

// some_promise_call().then(logger.log).catch(logger.log)
try {
    var results = some_call();
    logger.log(results);
} catch(e) {
    logger.log(e);
}

catch로거는 성공 로거 호출에서 예외를 처리합니다.

차이점이 너무 많습니다.

시도와 캐치에 대한 설명을 잘 이해하지 못합니다.

논쟁은 일반적으로 처리의 모든 단계에서 오류를 포착하고 체인에서 사용해서는 안된다는 것입니다. "antipattern"을 사용할 때 일부 콜백의 오류는 처리되지 않지만 모든 오류를 처리하는 최종 처리기는 하나만 있어야합니다.

그러나이 패턴은 실제로 매우 유용합니다. 정확하게이 단계에서 발생한 오류를 처리하고 오류가 발생하지 않은 경우 (예 : 오류를 복구 할 수없는 경우) 완전히 다른 작업을 수행하려는 경우. 이것이 제어 흐름을 분기 한다는 점에 유의 하십시오 . 물론 이것은 때때로 바람직하다.


다음과 관련하여 무엇이 문제입니까?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

콜백을 반복해야한다고 당신은 오히려 원합니다

some_promise_call()
   .catch(function(e) {
       return e; // it's OK, we'll just log it
   })
   .done(function(res) {
       logger.log(res);
   });

.finally()이것을 위해 사용 하는 것도 고려할 수 있습니다 .


7
이것은 며칠 동안 읽은 가장 유용한 설명입니다 (그리고 많이 읽었습니다). 나는 얼마나 감사하는지 설명 할 수 없습니다! :) 나는 당신이 성공 함수 내부에서도 오류.catch잡을 것입니다 . 여러 작업을 수행하지만 이것이 내 문제입니다. 어쨌든-정보 주셔서 감사합니다! 공유 할 의사가있는 온라인 커뮤니케이션 도구가 없어서 몇 가지 더 물어볼 수 있습니까? : P
Andrey Popov

2
이것이 당신에게 더 많은 투표를 제공하기를 바랍니다 . Promise이 사이트 에서 중요한 기계공에 대한 최고의 설명 중 하나입니다 .
패트릭 로버츠

2
.done()표준의 일부가 아닙니까? 적어도 MDN은 그 방법을 나열하지 않습니다. 도움이 될 것입니다.
ygoe

1
@ygoe 참으로. + 처리되지 않은 거부 감지에 done의해 기본적으로 사용되지 않는 블루 버드 then입니다.
Bergi

1
색맹에서 단지 참고 : 다이어그램은 이해가되지 않습니다 :)
Benny K

37

둘은 동일하지 않습니다. 차이점은 첫 번째 예제는 success핸들러 에서 발생한 예외를 포착하지 않는다는 것 입니다. 따라서 메소드가 해결 된 약속 만 반환 해야하는 경우가 종종 있지만 후행 catch핸들러 (또는 thensuccess매개 변수 가있는 다른 핸들러) 가 필요합니다 . 물론 then핸들러가 잠재적으로 실패 할 수있는 작업을 수행하지 않을 then수 있습니다. 이 경우 하나의 2 매개 변수 를 사용하는 것이 좋습니다.

그러나 당신이 연결된 텍스트의 요점은 then많은 비동기 단계를 연결하는 기능에서 콜백과 비교하여 대부분 유용하다는 것입니다. 실제로이 작업을 수행 할 때 2 매개 변수 형식의 then미묘하게 예상대로 작동하지 않습니다 위의 이유로. 미드 체인을 사용할 때 특히 직관적입니다.

많은 복잡한 비동기 작업을 수행하고 인정해야 할 것보다 이와 같은 구석에 부딪친 사람은이 안티 패턴을 피하고 별도의 처리기 접근 방식을 따르는 것이 좋습니다.


18

두 가지의 장단점을 살펴보면 상황에 적합한 계산 된 추측을 할 수 있습니다. 이것이 약속 이행에 대한 두 가지 주요 접근법입니다. 둘 다 플러스와 마이너스

캐치 접근법

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

장점

  1. 모든 오류는 하나의 catch 블록으로 처리됩니다.
  2. then 블록에서 예외를 잡습니다.
  3. 여러 성공 콜백 체인

단점

  1. 연결하는 경우 다른 오류 메시지를 표시하기가 어렵습니다.

성공 / 오류 접근

some_promise_call()
.then(function success(res) { logger.log(res) },
      function error(err) { logger.log(err) })

장점

  1. 세밀한 오류 제어가 가능합니다.
  2. db error, 500 error 등과 같은 다양한 범주의 오류에 대해 일반적인 오류 처리 기능을 사용할 수 있습니다.

Disavantages

  1. catch성공 콜백에 의해 발생한 오류를 처리하려면 여전히 다른 것이 필요합니다.

로그 파일을 사용하여 생산 문제를 디버깅 해야하는 사람에게는 성공 / 오류 접근 방식을 선호합니다.
Shane Rowatt

질문. 몇 가지 중 하나를 수행하는 비동기 호출을한다고 가정 해 보겠습니다 .1) 성공적으로 반환 (2xx 상태 코드), 2) 실패 (4xx 또는 5xx 코드) 반환하지만 자체 거부되지 않음, 3) 전혀 반환하지 않습니다 ( 인터넷 연결이 끊겼습니다). 사례 # 1의 경우 .then의 성공 콜백이 발생합니다. 사례 # 2의 경우 .then의 오류 콜백이 발생합니다. 사례 # 3의 경우 .catch가 호출됩니다. 이것은 올바른 분석입니까? 사례 # 2는 기술적으로 가장 까다로운 bc는 4xx 또는 5xx는 거부가 아니며 여전히 성공적으로 반환됩니다. 따라서 우리는 그것을 처리해야합니다. .... 이해가 정확합니까?
Benjamin Hoffman

"2 번 사례의 경우 .then의 오류 콜백이 발생합니다. 3 번 사례의 경우 .catch가 호출됩니다. 이것이 올바른 분석입니까?" 이것이 바로 페치의 작동 방식입니다
aWebDeveloper

2

간단한 설명 :

ES2018에서

catch 메소드가 onRejected 인수와 함께 호출되면 다음 단계가 수행됩니다.

  1. 약속이이 가치가되게하십시오.
  2. 돌아온다? 호출 (약속, "then",«정의되지 않음, onRejected»).

그것의 의미는:

promise.then(f1).catch(f2)

같다

promise.then(f1).then(undefiend, f2)

1

사용을 .then().catch()사용하면 워크 플로를 수행하는 데 필요한 Promise Chaining 을 활성화 할 수 있습니다 . 데이터베이스에서 일부 정보를 읽은 다음 비동기 API로 전달한 다음 응답을 조작하려고 할 수 있습니다. 응답을 데이터베이스로 다시 푸시 할 수 있습니다. 개념으로 이러한 모든 워크 플로를 처리하는 것은 가능하지만 관리하기가 매우 어렵습니다. 더 나은 해결책은 then().then().then().then().catch()모든 오류를 한 번에 잡아서 코드 의 유지 관리 성 을 유지할 수있게하는 것 입니다.


0

약속에 체인 성공 및 실패 처리기를 사용 then()하고 catch()도와줍니다. catch()에서 반환 한 약속에 따라 작동합니다 then(). 처리합니다.

  1. 약속이 거절 된 경우. 그림에서 # 3 참조
  2. then ()의 성공 핸들러에서 오류가 발생하면 아래 행 번호 4-7 사이입니다. 그림의 # 2.a를 참조하십시오 (실패 콜백은 then()이를 처리하지 않습니다).
  3. then ()의 실패 처리기에서 오류가 발생한 경우, 행 번호 8은 아래에 있습니다. 그림의 # 3.b를 참조하십시오.

1. let promiseRef: Promise = this. aTimetakingTask (false); 2. promiseRef 3. .then( 4. (result) => { 5. /* successfully, resolved promise. 6. Work on data here */ 7. }, 8. (error) => console.log(error) 9. ) 10. .catch( (e) => { 11. /* successfully, resolved promise. 12. Work on data here */ 13. });

여기에 이미지 설명을 입력하십시오

참고 : 많은 경우 실패 핸들러가 catch()이미 작성된 경우 실패 핸들러가 정의되지 않을 수 있습니다 . 편집 : 오류 처리기 가 정의 되지 않은 경우에만 reject()호출 catch()됩니다 . 그림의 # 3을로 확인하십시오 . 라인 # 8 및 9의 핸들러가 정의되지 않은 경우 호출됩니다.then()catch()

then()콜백이 돌보는 경우에 의해 반환 된 약속 에는 오류가 없으므로 의미 가 있습니다.


숫자 3에서 catch콜백 까지의 화살표가 잘못되었습니다.
Bergi

감사! then ()에 오류 콜백이 정의되어 있으면 호출되지 않습니다 (코드 스 니펫의 라인 # 8 및 # 9). # 3은 두 개의 화살표 중 하나를 호출합니다. 콜백이 돌보는 경우 then ()에 의해 반환 된 약속에는 오류가 없으므로 의미가 있습니다. 답을 수정했습니다!
VenCKi

-1

좋은 예입니다. 다음 코드 (첫 번째 약속이 해결 된 경우) :

Promise.resolve()
.then
(
  () => { throw new Error('Error occurs'); },
  err => console.log('This error is caught:', err)
);

다음과 동일합니다 :

Promise.resolve()
.catch
(
  err => console.log('This error is caught:', err)
)
.then
(
  () => { throw new Error('Error occurs'); }
)

그러나 첫 번째 약속이 거부되었으므로 이것은 동일하지 않습니다.

Promise.reject()
.then
(
  () => { throw new Error('Error occurs'); },
  err => console.log('This error is caught:', err)
);

Promise.reject()
.catch
(
  err => console.log('This error is caught:', err)
)
.then
(
  () => { throw new Error('Error occurs'); }
)

4
이해가되지 않습니다.이 답변을 제거해 주시겠습니까? 정답에서 오해의 소지가 있습니다.
Andy Ray

@AndyRay는 실제 응용 프로그램에서는 의미가 없지만 약속의 작업을 이해하는 것이 좋습니다.
ktretyak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.