2017-12-07 16 views
0

내 애플 리케이션에서 처리되지 않은 거부를 받고 있지만, 모든 코드가 오류 처리로 올바르게 래핑되었음을 확신했다. 주위를 파고 나면 async/await가 예상대로 작동하지 않는다는 것을 알게되었습니다. 기본적으로 내 비동기 함수는 동기화 오류를 throw하고 그 오류는 잡히지 않은 예외로 처리됩니다. 이것은 try catch에 내 코드를 명시 적으로 래핑 할 때도 발생하지만 오류를 throw하는 sync 메소드를 기다리는 경우에는 발생하지 않습니다.비동기로 동기 오류를 처리하는 방법은 무엇입니까?

그래서 여기 내 테스트 코드입니다 :

function test() { 
    async function one() { 
    try { 
     await three(); 
    } catch (error) { 
     console.log('caught', new Error().stack); 
     return error; 
    } 
    } 
    async function three() { 
    try { 
     throw new Error(); 
    } catch (e) { 
     console.log('caught', new Error().stack); 
     return Promise.reject(e); 
    } 
    } 

    one().then(function (result) { 
    console.log({result}); 
    }).catch(error => console.log({ error })); 
} 

process.on('unhandledRejection', (e) => console.log('not caught', e.stack)); 

test(); 

여기 내가 콘솔에서 볼 수있는 출력 :

not caught Error 
    at three$ (imports/access-control/execute-handler.js:25:13) 
    at tryCatch (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:65:40) 
    at GeneratorFunctionPrototype.invoke [as _invoke] (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:299:22) 
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as next] (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:117:21) 
    at tryCatch (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:65:40) 
    at invoke (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:155:20) 
    at /Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:198:11 
    at callInvokeWithMethodAndArg (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:197:16) 
    at AsyncIterator.enqueue (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:220:13) 
    at AsyncIterator.prototype.(anonymous function) [as next] (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:117:21) 
caught Error 
    at one$ (imports/access-control/execute-handler.js:11:29) 
    at tryCatch (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:65:40) 
    at GeneratorFunctionPrototype.invoke [as _invoke] (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:299:22) 
    at GeneratorFunctionPrototype.prototype.(anonymous function) [as throw] (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:117:21) 
    at tryCatch (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:65:40) 
    at invoke (/Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:155:20) 
    at /Users/joshuaohlman/Development/Xolvio/xspecs/modules/web-app/node_modules/regenerator-runtime/runtime.js:167:13 
    at /Users/joshuaohlman/.meteor/packages/promise/.0.8.9.ghfed++os+web.browser+web.cordova/npm/node_modules/meteor-promise/fiber_pool.js:32:39 
{ result: [Error] } 
(STDERR) [Error] [Function] 

그래서 내 질문이 예상되는 동작은 무엇입니까?

그렇다면 비동기 함수를 멋지게 래핑하여 동기식 및 비동기식 오류를 모두 잡아 내 자신을 처리하거나 거절 할 수 있도록 할 수 있습니다.

내 코드를 컴파일하는 데 바벨을 사용하고 있습니다.이 코드는 브라우저에서 코드를 실행하지만 노드에서 실행됩니다. 이 흥미로운 경우

, 여기에 내 코드의 컴파일 된 버전입니다 :

                           // 
function test() {                          // 6 
    function one() {                          // 7 
    return _regenerator2.default.async(function() {                 // 7 
     function one$(_context) {                      // 7 
     while (1) {                         // 7 
      switch (_context.prev = _context.next) {                  // 7 
      case 0:                         // 7 
       _context.prev = 0;                      // 7 
       _context.next = 3;                      // 7 
       return _regenerator2.default.awrap(three());                // 7 
                                 // 
      case 3:                         // 7 
       _context.next = 9;                      // 7 
       break;                         // 7 
                                 // 
      case 5:                         // 7 
       _context.prev = 5;                      // 7 
       _context.t0 = _context["catch"](0);                  // 7 
       console.log('caught', new Error().stack);                // 11 
       return _context.abrupt("return", _context.t0);               // 7 
                                 // 
      case 9:                         // 7 
      case "end":                        // 7 
       return _context.stop();                     // 7 
      }                           // 7 
     }                            // 7 
     }                            // 7 
                                 // 
     return one$;                          // 7 
    }(), null, this, [[0, 5]]);                      // 7 
    }                             // 7 
                                 // 
    function two() {                          // 15 
    return _regenerator2.default.async(function() {                 // 15 
     function two$(_context2) {                      // 15 
     while (1) {                         // 15 
      switch (_context2.prev = _context2.next) {                 // 15 
      case 0:                         // 15 
       _context2.prev = 0;                      // 15 
       _context2.next = 3;                      // 15 
       return _regenerator2.default.awrap(three());                // 15 
                                 // 
      case 3:                         // 15 
       _context2.next = 9;                      // 15 
       break;                         // 15 
                                 // 
      case 5:                         // 15 
       _context2.prev = 5;                      // 15 
       _context2.t0 = _context2["catch"](0);                 // 15 
       console.log('caught', new Error().stack);                // 19 
       return _context2.abrupt("return", _context2.t0);               // 15 
                                 // 
      case 9:                         // 15 
      case "end":                        // 15 
       return _context2.stop();                     // 15 
      }                           // 15 
     }                            // 15 
     }                            // 15 
                                 // 
     return two$;                          // 15 
    }(), null, this, [[0, 5]]);                      // 15 
    }                             // 15 
                                 // 
    function three() {                         // 23 
    return _regenerator2.default.async(function() {                 // 23 
     function three$(_context3) {                      // 23 
     while (1) {                         // 23 
      switch (_context3.prev = _context3.next) {                 // 23 
      case 0:                         // 23 
       _context3.prev = 0;                      // 23 
       throw new Error();                      // 23 
                                 // 
      case 4:                         // 23 
       _context3.prev = 4;                      // 23 
       _context3.t0 = _context3["catch"](0);                 // 23 
       console.log('caught', new Error().stack);                // 27 
       return _context3.abrupt("return", Promise.reject(_context3.t0));           // 23 
                                 // 
      case 8:                         // 23 
      case "end":                        // 23 
       return _context3.stop();                     // 23 
      }                           // 23 
     }                            // 23 
     }                            // 23 
                                 // 
     return three$;                         // 23 
    }(), null, this, [[0, 4]]);                      // 23 
    }                             // 23 
                                 // 
    one().then(function (result) {                      // 32 
    console.log({                          // 33 
     result: result                         // 33 
    });                            // 33 
    }).catch(function (error) {                       // 34 
    return console.log({                        // 34 
     error: error                          // 34 
    });                            // 34 
    });                             // 34 
}                              // 35 
                                 // 
process.on('unhandledRejection', function (e) {                  // 37 
    return console.log('not caught', e.stack);                   // 37 
});                             // 37 
test(); 

업데이트 내가 재생기 그래서이 가정의 최신 버전을 사용하여이 문제를 재현 할 수없는

버그에서이

내 재생기 또는 바벨 버전 또는 내 환경과 관련된 버전.

업데이트

랜스 Whatley는 내가 그 그러나 나는 확실히 기대하고 있지 않다 행동이 그 것이다, 그렇다면 확실하지 않다, 비동기 함수에서 약속을 반환하는 잘못된 있다고 지적 three() catch 절 내부의 콘솔 로그 문은 호출되지 않습니다.

답변

0

이것은 버그 였고 내 패키지 버전을 업데이트하면 해결되었습니다. 나는이 질문을 답장으로 남겨 두었습니다. 문제를 발견하고 해결하기 위해 놀랍도록 오랜 시간이 걸렸고 try/catch 블록으로 비동기/올바른 동작을 둘러싼 많은 혼란이있었습니다.

1

문제는 three() 비동기 기능입니다. catch 블록에 return Promise.reject(e) 대신에 try/catch를 세 가지 함수로 사용할 수없고 호출 메서드가 오류를 처리하도록하거나 three()에서 try/catch를 사용해야하는 경우 (예를 들어, 현재 호출중인 함수에 오류를 던지기 전에 현재 표시된 것처럼 출력), 로깅 후에 동일한 예외를 다시 throw합니다.

만 catch 블록에서 마지막 줄을 변경 다음을 것입니다 이런 식으로 행동하는 three()을 재정의의 예 :

// Rejects this async function, so the calling function will act as if the promise was rejected 
async function three() { 
    try { 
    throw new Error(); 
    } catch (e) { 
    console.log('caught', new Error().stack); 
    throw e; 
    } 
} 

또는

// Defines a function that returns a promise that's instantly rejected, so your calling method can handle the rejection 
async function three() { 
    throw new Error() 
} 

마지막 throw e; 효과적으로 거부 예상대로 행동하는 당신의 전화 기능에서 약속하십시오. return Promise.reject(e)을 실행하면 호출하는 비동기 함수가 거부되지 않고 부모 함수에서 확인 된 것처럼 Promise 거부 객체가 반환됩니다.

+0

흥미롭게도, 나는이 코드를 try catch (예 : 오류를 던지는 것)없이 원래 테스트했지만 현재 문제에 대해 당신이 맞다고 생각합니다. 그러나이 경우에도 catch 절은 호출되지 않으며 출력에 두 번째 'catch'콘솔 로그가 포함되지 않는다는 점에 유의해야합니다. – cwohlman

+0

두 번째 생각에 약속을 풀지 않고 약속을 그냥 풀지 않았습니까? 그래서 약속을 되 돌리는 것은 어떤 변화도 가져서는 안된다. 맞습니까? – cwohlman