그 전후에 어획물 배치


103

.catch중첩 약속에 BEFORE와 AFTER를 넣는 것의 차이점을 이해하는 데 어려움이 있습니다.

대안 1 :

test1Async(10).then((res) => {
  return test2Async(22)
    .then((res) => {
      return test3Async(100);
    }).catch((err) => {
      throw "ERROR AFTER THEN";
    });
}).then((res) => {
  console.log(res);
}).catch((err) => {
  console.log(err);
});

대안 2 :

test1Async(10).then((res) => {
   return test2Async(22)
     .catch((err) => {
        throw "ERROR BEFORE THEN";
      })
      .then((res) => {
        return test3Async(100);
      });
  }).then((res) => {
    console.log(res);
  }).catch((err) => {
    console.log(err);
  });

각 함수의 동작은 다음과 같습니다. number가 <0test2 이면 test1은 실패하고 number가 아니면 > 10test3은 실패합니다 100. 이 경우 test2는 실패 만합니다.

나는 실행하고 test2Async를 실패하게 만들려고했는데, BEFORE와 AFTER는 모두 같은 방식으로 작동하고 test3Async를 실행하지 않습니다. 누군가 다른 장소에 캐치를 배치하는 주요 차이점을 설명해 줄 수 있습니까?

각 기능 console.log('Running test X')에서 실행 여부를 확인합니다.

이 질문은 내가 게시 한 이전 스레드 때문에 발생합니다 중첩 된 콜백을 약속으로 바꾸는 방법? . 나는 그것이 다른 문제이고 다른 주제를 게시 할 가치가 있다고 생각합니다.


.then과 .catch는 약속을 바꿀 수 있습니다 ... 그래서 오해가 어디서 오는지 잘 모르겠습니다. .then 앞에 catch를 넣으면 .then 이전에 발생한 거부를 catch하고 .then은 .catch 내에서 발생하는 일을 기반으로 완료 / 실패 콜백을 실행하고 스왑 할 때 그 반대의 경우도 마찬가지입니다.
Kevin B

내 질문이 명확하지 않으면 죄송합니다. 하지만이 경우에 제가 말했듯이 두 경우 모두 동일하게 작동하므로 차이점을 볼 수 없습니다. 언제 우리가 캐치를 전에 넣어야하는지 그리고 그때 이후에 넣기로 결정한시기를 말씀해 주시겠습니까? 뒤에 두는 것은 정말 직관적이고 일반적으로 보입니다. 그냥 있는지 왜 때때로 우리는 그 전에 넣지
Zanko

그들이 똑같이 수행한다면, 그것은 단순히 각각의 행동이이 특정한 경우의 결과를 바꾸지 않기 때문입니다. 둘 중 하나를 약간만 변경하면 결과가 변경 될 수 있습니다.
Kevin B

"결과 변경"이란 무엇을 의미합니까? 정말 혼란
스러워서

예를 들어, 오류를 던지는 대신 아무것도하지 않은 경우 promise는 거부에서 해결로 전환됩니다. 물론 그 약속은 거부 된 약속이 아니라 해결 된 약속이기 때문에 결과를 바꿀 것입니다. (물론 이미 해결되지 않았다면 어차피 캐치가 실행되지 않았을 경우)
Kevin B

답변:


237

따라서 기본적으로이 둘의 차이점이 무엇인지 묻습니다 ( p이전 코드에서 생성 된 promise는 어디에 있습니까 ).

return p.then(...).catch(...);

return p.catch(...).then(...);

p가 해결하거나 거부 할 때 차이가 있지만 이러한 차이가 중요한지 여부는 .then()또는 .catch()핸들러 내부의 코드가 수행하는 작업에 따라 다릅니다 .

p해결 되면 어떻게 되나요?

첫 번째 체계에서 p해결되면 .then()처리기가 호출됩니다. 해당 .then()핸들러가 값이나 결국 해결되는 다른 promise를 반환하면 .catch()핸들러를 건너 뜁니다. 그러나 .then()핸들러가 결국 거부하는 promise를 던지거나 반환하는 경우 .catch()핸들러는 원래 promise의 거부와 핸들러 p에서 발생하는 오류 모두에 대해 실행됩니다 .then().

두 번째 체계에서는 p해결 될 때 .then()처리기가 호출됩니다. 해당 .then()핸들러가 결국 거부하는 프라 미스를 던지거나 리턴하면 .catch()핸들러가 체인에서 앞에 있기 때문에이를 포착 할 수 없습니다.

그래서 이것이 차이점 # 1입니다. 는 IF .catch()처리기 이후, 그것은 또한 내부 오류를 잡을 수 .then()처리기를.

p거부 하면 어떻게 되나요?

이제 첫 번째 체계에서 promise가 p거부되면 .then()핸들러를 건너 뛰고 .catch()예상대로 핸들러가 호출됩니다. .catch()처리기 에서 수행하는 작업에 따라 최종 결과로 반환되는 내용이 결정됩니다. .catch()핸들러 에서 값을 반환하거나 결국 해결되는 promise를 반환하면 오류를 "처리"하고 정상적으로 반환했기 때문에 promise 체인이 해결 된 상태로 전환됩니다. .catch()핸들러 에서 거부 된 promise를 던지거나 반환 하면 반환 된 promise는 거부 된 상태로 유지됩니다.

두 번째 체계에서 promise가 p거부되면 .catch()핸들러가 호출됩니다. 정상 값이나 결국 .catch()처리기 에서 해결되는 약속을 반환하면 (따라서 오류를 "처리") promise 체인이 해결 된 상태로 전환되고 .then()이후 처리기 .catch()가 호출됩니다.

이것이 차이점 # 2입니다. 는 IF .catch()핸들러가 전입니다, 그것은 오류를 처리하고 허용 할 수 .then()처리기가 여전히 전화를받을 수 있습니다.

사용시기 :

.catch()원래 프라 미스 p또는 .then()핸들러 에서 오류를 포착 할 수있는 핸들러 하나만 원하는 경우 첫 번째 스킴을 사용하고 거부에서 핸들러를 p건너 뛰어야 .then()합니다.

두 번째 스키마를 사용하면 원래 promise에서 오류를 포착 p하고 (조건에 따라 다름) 약속 체인이 해결 된대로 계속되도록 허용하여 .then()처리기 를 실행 합니다.

다른 옵션

다음 .then()과 같이 전달할 수있는 두 콜백을 모두 사용하는 다른 옵션이 있습니다 .

 p.then(fn1, fn2)

이렇게하면 fn1또는 중 하나만 fn2호출됩니다. 경우에 p결의 한 후 fn1호출됩니다. p거부 하면 fn2호출됩니다. 의 결과 변경은 전화 fn1fn2받을 수 없으며 그 반대도 마찬가지입니다. 따라서 핸들러 자체에서 어떤 일이 발생하는지에 관계없이 두 핸들러 중 하나만 호출되도록하려면 p.then(fn1, fn2).


17
질문은 구체적으로 대답하는 .then()및 의 순서에 관한 .catch()것입니다. 또한 세 번째 옵션을 언급하는 것이 적절하다고 생각하는 순서, 즉 성공 및 오류 처리기를 .then ()에 전달하는 방법에 대한 몇 가지 팁을 제공합니다 . 이 경우 최대 하나의 핸들러가 호출됩니다.
ArneHugo

7
@ArneHugo-좋은 제안입니다. 추가했습니다.
jfriend00 2017

그렇다면 Promise Chaining 중에 .then .catch .catch .then 종류의 시나리오를 작성할 수 있습니까?
Kapil Raghuwanshi

@KapilRaghuwanshi, 예, 실패 할 경우 기본값을 전달하는 데 사용할 수 있습니다. 즉, Promise.reject(new Error("F")).then(x => x).catch(e => {console.log(e); return [1]}).then(console.log)Promise.resolve([2]).then(x => x).catch(e => [1]).then(console.log)
CervEd

1
@DmitryShvedov-내가 짐작했듯이 이것은 잘못되었습니다 .then(this.setState({isModalOpen: false})). .then()괄호 안의 코드가 즉시 실행되도록 함수 참조를 전달하지 않습니다 (Promise가 해결되기 전에). 이어야합니다 .then(() => this.setState({isModalOpen: false})).
jfriend00

31

jfriend00의 대답 은 훌륭하지만 유사한 동기 코드를 추가하는 것이 좋은 생각이라고 생각했습니다.

return p.then(...).catch(...);

동기식과 유사합니다.

try {
  iMightThrow() // like `p`
  then()
} catch (err) {
  handleCatch()
}

iMightThrow()던지지 않으면 then()호출됩니다. 던지면 (또는 then()자체적으로 던지면) handleCatch()호출됩니다. catch블록 then이 호출 여부를 제어하지 않는 방법을 확인하십시오 .

반면에

return p.catch(...).then(...);

동기식과 유사합니다.

try {
  iMightThrow()
} catch (err) {
  handleCatch()
}

then()

이 경우 iMightThrow()던지지 않으면 then()실행됩니다. throw되면 호출 handleCatch()여부를 결정해야 then()합니다. handleCatch()다시 throw되면 then()호출되지 않으므로 예외가 호출자에게 즉시 throw됩니다. handleCatch()문제를 정상적으로 처리 할 수 있으면 then()호출됩니다.


이 좋은 설명입니다하지만 당신은 고아를 래핑 수 then()A의finally{...}
tyskr

2
@ 82Tuskers, 확실합니까? 내가 넣어 경우 then()finally{...}, 잘못 경우에도 호출 할 수 없습니다 것입니다 handleCatch()던져? 내 목표는 예외 처리의 다양한 방법으로 제안하지, 유사 동기 코드를 보여 것을 명심하십시오
akivajgordon

따라서 모든 경우를 처리하고 싶지만 여전히 .then () 체인을 사용하려면 .then (무언가) .catch (log err 및 update state) .then (do another thing) .catch (log err) 우리는 모든 지점에서 잡으려고 시도하지만 stmnts를 계속 실행합니까?
anna
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.