「不要な await」を消すと何が嬉しいのか
await は便利ですが、
「なくてもいい場所に書いてしまうと、わざわざ処理を遅くしている」
ことがあります。
パフォーマンス最適化でよく効くのが、
この「不要な await」を見つけて消すことです。
ここでいう「不要な await」は、ざっくり言うと
「待つ必要がないのに、わざわざ待っている await」
のことです。
まずは「本当に必要な await」との違いを押さえる
await が必要な典型パターン
これは「必要な await」です。
async function getUserName() {
const user = await fetchUser(); // user が必要
return user.name;
}
JavaScriptuser.name を返したいので、fetchUser() の結果が返ってくるまで待たないといけません。
「この行の後ろで、結果(値)をすぐ使う」
こういう場所の await は必要です。
不要な await の典型パターン(イメージ)
逆に、こういうのは怪しいです。
async function logUser() {
await fetchUser(); // 結果を使っていない
console.log("done");
}
JavaScriptfetchUser() の返り値をどこでも使っていないのに、await して 1000ms 待ってから "done" を出しています。
もし「とにかくリクエストだけ飛ばせばよくて、
ログはすぐ出していい」なら、await は不要です。
async function logUser() {
fetchUser(); // 待たない
console.log("done");
}
JavaScriptこの違いが、
「不要な await を消す」という話の出発点です。
パターン1:戻り値をそのまま返すだけの await
よくある「ただの中継」になっている関数
次のようなコード、かなりよく見かけます。
async function getData() {
const result = await fetchData();
return result;
}
JavaScriptこれは、こう書いても意味が同じです。
function getData() {
return fetchData();
}
JavaScriptawait してから return しているだけで、
「結果を加工しているわけではない」 ので、
関数の外から見た挙動は変わりません。
async も await もいらないパターンです。
もう少し極端な例だと:
async function getData() {
return await fetchData();
}
JavaScriptこれは完全に無駄な await です。return await は、エラーハンドリングの特殊なケースを除けば、
基本的に「不要」と考えてOKです。
ここが重要です。
「中で何もせずに“そのまま返すだけ”なら、await せずに Promise を返していい」。async function にした瞬間、戻り値は自動的に Promise になる。
パターン2:並列にできるのに、順番に await している
直列に待ってしまっている例
async function loadPage() {
const user = await fetchUser(); // 1秒かかる
const posts = await fetchPosts(); // 1秒かかる
const notifications = await fetchNotifications(); // 1秒かかる
return { user, posts, notifications };
}
JavaScriptこれだと、
1秒 + 1秒 + 1秒 = 約3秒 かかります。
でも、これらが互いに独立しているなら、
「順番に await」する必要はありません。
async function loadPage() {
const userPromise = fetchUser();
const postsPromise = fetchPosts();
const notificationsPromise = fetchNotifications();
const [user, posts, notifications] = await Promise.all([
userPromise,
postsPromise,
notificationsPromise,
]);
return { user, posts, notifications };
}
JavaScriptこうすると、
3つが同時に走るので、
「1秒くらい」で終わります(最も遅いものに合わせる)。
ここでの「不要な await」は、
「本当は並列にできるのに、
1つずつ順番に await してしまっていること」です。
ここが重要です。
「結果同士が依存していないのに、const a = await ...; const b = await ...; と書いていないか?」
と疑ってみる。
並列にできるなら、await の位置を“まとめる”ことで待ち時間を減らせる。
パターン3:呼び出し側で await するのに、中でも await している
二重に待ってしまっているイメージ
async function fetchUserData() {
const user = await fetchUser();
return user;
}
async function main() {
const user = await fetchUserData();
console.log(user);
}
JavaScriptfetchUserData の中で await して、
さらに main でも await しています。
これは、
function fetchUserData() {
return fetchUser();
}
async function main() {
const user = await fetchUserData();
console.log(user);
}
JavaScriptと書いても、main の挙動は変わりません。
もちろん、fetchUserData の中で何か加工するなら話は別です。
async function fetchUserData() {
const user = await fetchUser();
return {
id: user.id,
name: user.name,
};
}
JavaScriptこういう場合の await は必要です。
ここがポイントです。
「呼び出し側で await する前提なら、中の関数は“Promise を返すだけ”でよい場面が多い。
中で await しているのに、何も加工していないなら不要な await を疑う。」
パターン4:fire-and-forget なのに await している
「結果を使わないのに待っている」ケース
例えば、ログ送信やトラッキングのように、
「とりあえずサーバーに投げておけばよくて、
結果は特に使わない」処理があります。
async function trackEvent(event) {
await sendToAnalytics(event);
console.log("tracked");
}
JavaScriptもし「console.log("tracked") をすぐ出してよい」なら、await は不要です。
async function trackEvent(event) {
sendToAnalytics(event); // 待たない
console.log("tracked");
}
JavaScriptただし、
「ページ遷移前に絶対送信を完了させたい」など、
「完了を保証したい」 場面では await が必要です。
ここが重要です。
「この非同期処理の“完了”を、本当に待つ必要があるか?」
「投げるだけでよい処理にまで、反射的に await を付けていないか?」
を一度立ち止まって考える。
不要な await を消すときの“安全確認”の視点
1. その結果をすぐ使っているか?
await の直後の行で、その結果を使っているなら、
基本的には必要です。
const data = await fetchData();
console.log(data); // ここで使っている → 必要
JavaScript使っていないなら、
「本当に待つ必要があるのか?」を疑ってみる価値があります。
2. 順番が入れ替わると困るか?
await を外したり、Promise.all にまとめたりすると、
「どの処理が先に終わるか」が変わることがあります。
順番が意味を持つ処理(残高更新、連番発行など)は、
絶対に直列であるべきです。
「順番が変わっても意味が変わらないか?」
これを自分に問いかけてください。
3. エラーの扱いはどうなるか?
await を外すと、
その Promise のエラーが「どこで捕まるか」も変わります。
async function main() {
doSomething(); // await しない
}
JavaScriptこの場合、doSomething 内のエラーはmain の try/catch では拾えません。
async function main() {
try {
await doSomething(); // ここなら拾える
} catch (e) {
console.error("エラー:", e);
}
}
JavaScriptここが重要です。
「パフォーマンスのために await を消すときは、
“エラーの伝わり方”も一緒に変わる」ことを意識する。
“エラーをちゃんと扱いたい処理”は、あえて await しておく価値がある。
初心者として「不要 await の削除」で本当に押さえてほしいこと
最後に、判断の軸をコンパクトにまとめます。
その await の「結果」をすぐ使っているなら、基本的に必要
ただ返すだけ・何も加工していないなら、await を外して Promise をそのまま返せる
互いに独立した非同期処理を、順番に await していないかを疑う
結果を使わない処理(ログ送信など)にまで reflex 的に await を付けていないかを見る
await を消すと「エラーの捕まり方」と「実行順」が変わることを忘れない
おすすめの練習は、
自分の書いた async 関数を一つ選んで、
中の await を一個ずつ眺めながら、こう自問することです。
「この await は、“何のために”必要なんだっけ?」
その問いに即答できない await は、
パフォーマンス改善のチャンスかもしれません。
そうやって await を「なんとなく付ける記号」から、
「意味を持って置くスイッチ」 に変えていけると、
非同期コードの質と速さが、目に見えて変わっていきます。
