Edited at

async/await の例外処理まとめ

More than 1 year has passed since last update.

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


まとめ


  • 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 => {}) で拾うことができる