Promise catch에서 오류를 다시 던짐


88

튜토리얼에서 다음 코드를 찾았습니다.

promise.then(function(result){
    //some code
}).catch(function(error) {
    throw(error);
});

나는 약간 혼란 스럽습니다. catch 호출이 어떤 일을 수행합니까? 그것은 단순히 잡힌 것과 같은 오류를 던지기 때문에 아무런 영향을 미치지 않는 것 같습니다. 나는 이것을 정규적인 try / catch가 어떻게 작동하는지에 기초한다.


튜토리얼에 대한 링크를 제공 할 수 있습니까? 도움이 될 추가 컨텍스트가있을 수 있습니다.
Igor

@Igor 할 수 없습니다, Pluralsight에 있습니다. 이것은 아마도 오류 처리 논리에 대한 자리 표시 자일까요?
Tyler Durden

그것이 내가 더 이상 아무것도하지 않고 오류를 호출자에게 전달하기 때문에 내가 추측하는 것입니다.
Igor

1
@TylerDurden 나는 당신이 자리 표시 자에 대해 옳다고 생각합니다.
Jared Smith

@TylerDurden, 나는 그것이 자리 표시 자라고 생각합니다. 오류를 형식화 / 정규화하는 방법을 보여 주려고 할 수 있습니다. 기본적으로 try { ... }catch(error){ throw new Error("something went wrong") }. 또는 약속과 오류가 호환된다는 것을 보여주기 위해 (적어도 그 정도 는 그렇습니다 ) . 그러나 현재 구현에서는 어리석은 일입니다. 당신 말이 맞아요, 그것은 아무것도하지 않고 상속 클래스에서 덮어 쓰기를 가능하게하기 위해 OOP에 추가하는 후크와도 같지 않습니다. 나는 그것이 무언가를하자마자 catch-block을 추가 할 것이지만 자리 표시 자뿐만 아니라 그렇게하지 않습니다.
Thomas

답변:


124

당신이 보여줄 때 알몸으로 잡고 던지는 것은 의미가 없습니다. 코드 추가 및 느린 실행 외에는 유용한 작업을 수행하지 않습니다. 따라서 다시 .catch()던지려는 경우에서 원하는 작업 .catch()이 있어야 합니다 . 그렇지 않으면 .catch()전체를 제거해야합니다 .

일반적인 구조의 일반적인 요점 .catch()은 오류를 기록하거나 파일 닫기와 같은 일부 상태를 정리 하는 것과 같은 작업 을 실행 하려고하지만 약속 체인이 거부 된 상태로 계속되기를 원할 때입니다.

promise.then(function(result){
    //some code
}).catch(function(error) {
    // log and rethrow 
    console.log(error);
    throw error;
});

튜토리얼에서는 사람들에게 오류를 포착 할 수있는 위치를 보여 주거나 오류를 처리하는 개념을 가르치고 다시 던지기 위해있을 수 있습니다.


잡기 및 다시 던지기에 대한 몇 가지 유용한 이유는 다음과 같습니다.

  1. 오류기록하고 싶지만 약속 체인을 거부 된 상태로 유지합니다.
  2. 오류를 다른 오류로 바꾸고 싶습니다. (체인의 끝에서 종종 쉽게 오류 처리를 위해). 이 경우 다른 오류가 다시 발생합니다.
  3. 약속 체인이 계속되기 전에 (예 : 닫기 / 사용 가능한 리소스) 많은 처리수행하고 싶지만 약속 체인이 거부 된 상태로 유지되기를 원합니다.
  4. 실패가있는 경우 약속 체인의이 지점에서 디버거대한 중단 점을 배치 할 지점을 원합니다 .

그러나 catch 핸들러에 다른 코드가없는 동일한 오류를 일반 catch 및 rethrow는 정상적인 코드 실행에 유용한 작업을 수행하지 않습니다.


제 생각에는 좋은 예가 아닙니다. 이러한 접근 방식을 사용하면 1 개의 오류에 대해 여러 로깅을 쉽게 얻을 수 있습니다. 자바에서는 자바 throw new Exception(periousException);스크립트가 중첩 오류를 지원하는지 여부를 알 수 없지만 어쨌든 "로그 앤 던지기"는 나쁜 습관입니다.
Cherry

26
@Cherry-이것은 일반적으로 나쁜 습관이라고 말할 수 없습니다. 모듈이 자신의 방식으로 자신의 오류를 기록하고자 할 때가 있으며 이것이이를 수행하는 한 가지 방법입니다. 게다가, 나는 이것을 권장하지 않습니다 . .catch().NET Framework에서 SOMETHING 다른 작업을 수행하지 않는 한 캐치 내부에 동일한 오류가 발생하고 동일한 오류를 던질 이유가 없다고 설명하고 있습니다 .catch(). 이것이이 답변의 요점입니다.
jfriend00

일반적으로 예외는 추상화 수준에 맞아야합니다. 예를 들어 db 관련 예외를 포착하고 호출자가 처리 할 "서비스"예외와 같은 것을 던지는 것은 완벽하게 괜찮습니다. 이것은 낮은 수준의 예외에 대한 세부 정보를 노출하지 않을 때 특히 유용합니다.
maxTrialfire 2018

3
잡거나 던지는 또 다른 좋은 이유는 특정 오류를 처리하고 다른 모든 것을 다시 던지기 위해서입니다.
Jasper

2
@SimonZyx-예, .finally()매우 유용 할 수 있지만 때로는 리소스가 오류가 아닌 경로에서 이미 처리되므로 .catch()여전히 리소스 를 닫을 수 있습니다. 상황에 따라 다릅니다.
jfriend00

15

.then().catch()메서드는 모두 Promises를 반환하며, 두 핸들러 중 하나에서 Exception을 throw하면 반환 된 promise는 거부되고 Exception은 다음 거부 핸들러에서 포착됩니다.

다음 코드에서는 첫 번째 예외가 발생하고 두 번째 예외가 발생 .catch()합니다 .catch().

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
});

두 번째 .catch()는 이행 된 Promised를 반환하고 .then()핸들러를 호출 할 수 있습니다.

new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');
        
    console.log('Do this'); // Never reached
})
.catch(() => {
    console.log('Something failed');
    throw new Error('Something failed again');
})
.catch((error) => {
    console.log('Final error : ', error.message);
})
.then(() => {
    console.log('Show this message whatever happened before');
});

유용한 참조 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Chaining_after_a_catch

도움이 되었기를 바랍니다!


4

생략하면 큰 차이가 없습니다. catch메서드 호출을 완전히 .

추가되는 유일한 것은 추가 마이크로 태스크이며, 실제로는 catch조항 없이 실패한 약속의 경우보다 나중에 약속의 거부를 알 수 있음을 의미합니다 .

다음 스 니펫은이를 보여줍니다.

var p;
// Case 1: with catch
p = Promise.reject('my error 1')
       .catch(function(error) {
          throw(error);
       });

p.catch( error => console.log(error) );
// Case 2: without catch
p = Promise.reject('my error 2');

p.catch( error => console.log(error) );

두 번째 거부가 첫 번째 거부 전에 어떻게보고되는지 확인하십시오. 이것이 유일한 차이점입니다.


3

따라서 귀하의 질문은 "프로 미스 체인에서 .catch()메소드가 수행하는 작업은 무엇입니까?"입니다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw

throw 문은 "중지되고 (throw 후 문이 실행되지 않음) 제어가 호출 스택의 첫 번째 catch 블록으로 전달됩니다. 호출자 함수 중에 catch 블록이 없으면 프로그램이 종료됩니다."

Promise 체인에서 .then()메소드는 어떤 유형의 데이터 청크를 반환합니다. 이 청크 반환은 약속을 완료합니다. 데이터가 성공적으로 반환되면 약속이 완료됩니다. .catch()같은 방식으로 방법을 생각할 수 있습니다 . .catch()그러나 실패한 데이터 검색을 처리합니다. throw 문은 약속을 완료합니다. 때때로, 당신은 .catch((err) => {console.log(err))} 약속 체인을 완성 할 개발자들이 사용 하는 것을 보게 될 것입니다.


0

실제로 다시 던질 필요가 없습니다. Promise.catch를 비워 두십시오. 그렇지 않으면 거부 처리를 취소 한 다음 코드를 try catch로 래핑 한 다음 전달되는 오류를 자동으로 포착합니다.

try{
  promise.then(function(result){
    //some code
  }).catch(function(error) {
    //no need for re throwing or any coding. but leave this as this otherwise it will consider as un handled
  });
}catch(e){
  console.log(e);
  //error can handle in here
}

0

promise 체인에서는 .catch를 사용하는 것이 좋습니다.

ex 함수 f2에서 : .then (...). catch (e => reject (e));

  • test1-try catch 사용
  • test2-try 또는 .catch없이
  • test3-.catch 사용

function f1() {
    return new Promise((resolve, reject) => {
        throw new Error('test');
    });
}

function f2() {
    return new Promise((resolve, reject) => {
        f1().then(value => {
            console.log('f1 ok ???');
        }).catch(e => reject(e));
    });
}

function test1() {
    console.log('test1 - with try catch - look in F12');
    try {
      f2().then(() => { // Uncaught (in promise) Error: test
        console.log('???'); });
    } catch (e) {
      console.log('this error dont catched');
    }
}

function test2() {
    console.log('test2 - without try or .catch - look in F12');
    f2(); // Uncaught (in promise) Error: test
}

function test3() {
  console.log('test3 - with .catch');
  f2().then(value => {
    console.log('??');
  }).catch(e => {
    console.log(' now its ok, error ', e);
  })
}

setTimeout(() => { test1(); 
  setTimeout(() => { test2(); 
    setTimeout(() => { test3(); 
    }, 100);
  }, 100);
}, 100);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.