2017-12-07 8 views
0

私はアプリでいくつかの処理されていない拒否を得ていますが、すべてのコードがエラー処理で正しくラップされていることは間違いありません。周りを掘り起こした後、私はasync/awaitが期待通りに動作していないことに気付きました。基本的に私の非同期関数は同期エラーをスローし、そのエラーはキャッチされない例外として扱われます。これは、コードをtryキャッチで明示的にラップするときにも発生しますが、エラーをスローする同期メソッドを待っているときには発生しません。async awaitで同期エラーを処理する方法は?

は、だからここに私のテストコードです:

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] 

だから私の質問は、この予想される動作はありますか?

もしそうなら、非同期関数をきちんとラップして、同期エラーと非同期エラーの両方をキャッチして自分自身で処理したり、拒否として渡したりすることができます。

私はコードをコンパイルするためにbabelを使用しています(この特定のビットはノードで実行されますが、ブラウザでもコードを実行します)。

それが面白い場合は、ここに私のコードのコンパイルされたバージョンです:

                           // 
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ブロックを使ってasync/awaitの正しい動作を取り巻く多くの混乱があります。

1

問題はthree()非同期機能です。キャッチブロックにreturn Promise.reject(e)の代わりに、3つの関数でtry/catchを使用したり、呼び出しメソッドでエラーを処理したり、three()でtry/catchを使用する必要がある場合(たとえば、あなたが現在呼び出している関数にエラーを投げる前に現在行っているように出力します)、ログの後に同じ例外を再びスローします。

このように動作するthree()を再定義の例は、あなたのcatchブロック内の最後の行を変更するには、次のようになります。

// 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)を実行すると、呼び出し側のasync関数は拒否されず、親関数で解決されたかのようにプロミス拒否オブジェクトが返されます。

+0

興味深いことに、私は当初、このコードをtry catchなしでテストしましたが(現在はエラーを投げているなど)、現在の問題について正しいと思います。しかし、そのような場合でも、catch節が呼び出されることはないことに注意することが重要です。出力に2番目の 'catch'コンソールログが含まれないことに注意してください。 – cwohlman

+0

2番目の考えでは、約束を解除するだけで約束を解除しないのですか?だから、約束を返すべきではないでしょうか? – cwohlman

関連する問題