50708


asyncの挙動について、[MDNのドキュメント](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function)だけでは分からなかったので教えてください。

例えば、以下の try-catchはPromiseのrejectをcatchしません。

[code]

    try {
        (async () =>{
                await Promise.reject()
        })()
    }catch (e){
        console.log('ERROR!', e) // これは出力されない。代わりに...
        /*
            (node:66365) UnhandledPromiseRejectionWarning: undefined
            (node:66365) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
            (node:66365) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
        */
    }
    
[/code]

一方で、try-catchブロックをasyncの内側に持ってくるとcatchします。

[code]

    (async () =>{
        try {
            await Promise.reject()
        }catch (e){
            console.log('ERROR!', e) //これが出力される
        }
    })()
    
[/code]

どのようにしてこの違いが生まれるのかご教示いただけないでしょうか。  
参考になる考え方、資料でも結構です。よろしくお願いいたします。


CC BY-SA 4.0
2018-11-28T06:04:30.963
50706
2019-07-28T11:08:27.177
2019-07-28T11:08:27.177
32986
26110
question
javascript promise
asyncの中でだけ、try-catchがrejectedされたPromiseをcatchできる理由がわからない。


まず、1番目の例でrejectがキャッチされないことは2つの観点から説明できます。

  1. `try`文は中で発生した例外（エラー）をキャッチできるものです。そして、Promiseのrejectは例外ではありません。  
この`try`の中でやっていることは全体として見ると「async関数を呼び出す」というだけであり、async関数の中での失敗は外側に伝播するのではなく返り値のPromiseのrejectionという形で現れます。

  2. この`try`の中ではasync関数が実行されていますが、async関数の実行は一般には非同期的に行なわれます。つまり、実行が完了するのは今動いているプログラムの実行が完了した後となります。  
2については以下のコードで確かめられます。

[code]     try {

        (async () =>{
                await Promise.reject()
        })()
    }catch (e){
        console.log('ERROR!', e) // これは出力されない。代わりに...
    }
    console.log('END');
    
[/code]

こうすると、UnhandledPromiseRejectingWarning云々というのは`END`よりも後に表示されますから、Promiseのrejectionが発生しているのは「tryの中」ではなく「tryの実行終了後」であることが分かります。このようなものは`try`でキャッチできません。

* * *

続いて2番目の例については、一言で言えば
**`await`がPromiseのrejectionを例外に変換しています**。これが、Promiseのrejectionを`try`でキャッチできる理由です。

そもそも`await`というのは、非同期の処理（Promiseの解決）をその場で待つことで同期処理のように扱うことができる式です。Promiseが成功（fulfill）したら`await`式の結果としてPromiseの値が得られる一方で、Promiseが失敗(reject)したら`await`式から例外が発生します。  
（その代わり`await`はasync関数の中でしか使うことができず、`await`がその場で待つとasync関数全体の実行が非同期的になります。）

1番目の例でも`await`を同様に使っているのでここでも例外は発生しているのですが、その例外は`try`よりも前にasync関数のスコープに捕捉されてasync関数の結果のPromiseのrejectionに再変換されています。


CC BY-SA 4.0
2018-11-28T06:27:23.980
50708
2018-11-28T10:04:23.783
2018-11-28T10:04:23.783
30079
30079
50706
answer