Help us understand the problem. What is going on with this article?

async/await の例外処理まとめ

こんがらがったので、ひと通りのパターンを検証してみた。

まとめ

  • async function をただ呼び出すときは try catch は意味をなさない
  • await 付きで呼び出せば try catch が意味をなす
  • await の有無にかかわらず .catch(e => {}) で拾うことができる

確認環境

  • Node.js
    • v8.9.4

基本(例外なしの挙動)

// 100ms 後に resolve される Promise を返す
const asyncFunction = (v) => new Promise(r => setTimeout(() => r(v), 100));

const nothing = async () => {
    asyncFunction('nothing');
};

const justReturn = async () => {
    return asyncFunction('just return');
};

const returnWithAwait = async () => {
    return await asyncFunction('return with await');
};

(async () => {
    console.log(nothing());
    console.log(justReturn());
    console.log(returnWithAwait());

    console.log(await nothing());
    console.log(await justReturn());
    console.log(await returnWithAwait());
})();

実行結果
Promise { undefined }
Promise { <pending> }
Promise { <pending> }
undefined
just return
return with await

async function は Promise を返す。
async function 内での await の有無は影響しない。

async function 内での例外処理

// 100ms 後に reject される Promise を返す
const asyncFunction = (v) => new Promise((_, r) => setTimeout(() => r(v), 100));

const nothing = async () => {
    asyncFunction('nothing');
};

const justAwait = async () => {
    await asyncFunction('just await');
};

const justTryCatch = async () => {
    try {
        asyncFunction('just try catch');
    } catch (e) {
        console.error(e);
    }
}

const tryCatchWithAwait = async () => {
    try {
        await asyncFunction('try catch with await');
    } catch (e) {
        console.error(e);
    }
}

const justCatch = async () => {
    return asyncFunction('just catch').catch(e => console.error(e));
}

const awaitCatch = async () => {
    return await asyncFunction('await catch').catch(e => console.error(e));
}

nothing();
justAwait();
justTryCatch();
tryCatchWithAwait();
justCatch();
awaitCatch();
実行結果
just catch
await catch
try catch with await
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): nothing
(node:1) [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.
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): just try catch
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): just await

※エラーにならずにに文字列を出力できているものは、例外を拾うことができている、という認識。以下同様。

await 付きで呼び出して try catch するか、 .catch() するかで例外を拾うことができる。
.catch() するときは、await の有無は影響しない。

async function を呼び出す側の例外処理

先ほどの例で、例外を拾えていなかったものが対象。

// 100ms 後に reject される Promise を返す
const asyncFunction = (v) => new Promise((_, r) => setTimeout(() => r(v), 100));

const nothing = async () => {
    asyncFunction('nothing');
};

const justAwait = async () => {
    await asyncFunction('just await');
};

const justTryCatch = async () => {
    try {
        asyncFunction('just try catch');
    } catch (e) {
        console.error(e);
    }
}

//----------------
// just try catch
//----------------
try {
    nothing();
} catch (e) {
    console.error('just try catch: ' + e);
}

try {
    justAwait();
} catch (e) {
    console.error('just try catch: ' + e);
}

try {
    justTryCatch();
} catch (e) {
    console.error('just try catch: ' + e);
}

//------------
// just catch
//------------
nothing().catch(e => console.error('just catch: ' + e));
justAwait().catch(e => console.error('just catch: ' + e));
justTryCatch().catch(e => console.error('just catch: ' + e));


(async () => {
    //----------------------
    // try catch with await
    //----------------------
    try {
        await nothing();
    } catch (e) {
        console.error('try catch with await: ' + e);
    }

    try {
        await justAwait();
    } catch (e) {
        console.error('try catch with await: ' + e);
    }

    try {
        await justTryCatch();
    } catch (e) {
        console.error('try catch with await: ' + e);
    }

    //-------------
    // await catch
    //-------------
    await nothing().catch(e => console.error('await catch: ' + e));
    await justAwait().catch(e => console.error('await catch: ' + e));
    await justTryCatch().catch(e => console.error('await catch: ' + e));
})();
実行結果
just catch: just await
try catch with await: just await
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): nothing
(node:1) [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.
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): just try catch
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 3): nothing
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): just try catch
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 5): nothing
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 6): just await
await catch: just await
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 7): just try catch
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 8): nothing
(node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 9): just try catch

次のような場合のみ例外を拾える。

const justAwait = async () => {
    await asyncFunction('just await');
};

// 以下のどれか
justAwait().catch(e => {});

(async () => {
    try {
        await justAwait();
    } catch (e) {
    }

    await justAwait().catch(e => {});
})();

まとめ(再掲)

  • async function をただ呼び出すときは try catch は意味をなさない
  • await 付きで呼び出せば try catch が意味をなす
  • await の有無にかかわらず .catch(e => {}) で拾うことができる
willgate
ウィルゲートが理想とする社会は、一人ひとりが自身の『will(意志、想い、やりたいこと)』を実現できる社会です。
https://willgate.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした