MeWrite Docs

await is only valid in async functions

asyncではない関数でawaitを使用した場合のエラー

概要

asyncキーワードが付いていない関数内でawaitを使用した場合に発生するエラーです。awaitは非同期関数(async function)内でのみ使用できます。

エラーメッセージ

SyntaxError: await is only valid in async functions and the top level bodies of modules
SyntaxError: Unexpected reserved word
SyntaxError: 'await' expressions are only allowed within async functions

原因

  1. asyncの付け忘れ: 関数宣言にasyncがない
  2. コールバック関数: map/forEachなどのコールバックにasyncがない
  3. トップレベルawait: モジュールでない環境でのトップレベルawait
  4. アロー関数: アロー関数にasyncがない
  5. クラスメソッド: メソッドにasyncがない

解決策

1. 関数にasyncを追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Bad: asyncがない
function fetchData() {
  const response = await fetch('/api/data');  // Error
  return response.json();
}

// Good: asyncを追加
async function fetchData() {
  const response = await fetch('/api/data');
  return response.json();
}

2. アロー関数の場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Bad: asyncがない
const fetchData = () => {
  const data = await getData();  // Error
  return data;
};

// Good: asyncを追加
const fetchData = async () => {
  const data = await getData();
  return data;
};

3. コールバック関数の場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Bad: mapのコールバックにasyncがない
const results = items.map((item) => {
  const data = await processItem(item);  // Error
  return data;
});

// Good: コールバックにasyncを追加
const results = await Promise.all(
  items.map(async (item) => {
    const data = await processItem(item);
    return data;
  })
);

4. forEachでは使えない

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Bad: forEachはawaitを待たない
items.forEach(async (item) => {
  await processItem(item);  // 動作するが順番が保証されない
});

// Good: for...of を使用
for (const item of items) {
  await processItem(item);  // 順番に実行
}

// Good: 並列実行したい場合
await Promise.all(items.map(item => processItem(item)));

5. クラスメソッド

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// Bad: メソッドにasyncがない
class DataService {
  fetchData() {
    const data = await fetch('/api/data');  // Error
    return data;
  }
}

// Good: asyncを追加
class DataService {
  async fetchData() {
    const data = await fetch('/api/data');
    return data.json();
  }
}

6. トップレベルawait(ES Modules)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 通常のスクリプトではエラー
const data = await fetch('/api/data');  // Error

// ES Modules では使用可能
// package.json に "type": "module" が必要
// または .mjs 拡張子

// index.mjs
const data = await fetch('/api/data');
console.log(data);

7. IIFEパターン

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// トップレベルで非同期処理を実行
(async () => {
  const data = await fetchData();
  console.log(data);
})();

// または
async function main() {
  const data = await fetchData();
  console.log(data);
}
main();

8. イベントハンドラ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Bad: asyncがない
button.addEventListener('click', (event) => {
  const result = await submitForm();  // Error
});

// Good: asyncを追加
button.addEventListener('click', async (event) => {
  const result = await submitForm();
  console.log(result);
});

9. Promiseチェーンとの使い分け

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// async/await を使う場合
async function fetchUserData(userId) {
  const user = await getUser(userId);
  const posts = await getPosts(user.id);
  return { user, posts };
}

// Promise チェーンを使う場合
function fetchUserData(userId) {
  return getUser(userId)
    .then(user => getPosts(user.id)
      .then(posts => ({ user, posts }))
    );
}

// 両方組み合わせ
async function fetchUserData(userId) {
  const user = await getUser(userId);
  return getPosts(user.id).then(posts => ({ user, posts }));
}

10. エラーハンドリング

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// try-catch を使用
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error('Network error');
    }
    return await response.json();
  } catch (error) {
    console.error('Error:', error);
    throw error;
  }
}

// .catch() を使用
fetchData()
  .then(data => console.log(data))
  .catch(error => console.error(error));

11. 並列実行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 順次実行(遅い)
async function sequential() {
  const a = await fetchA();
  const b = await fetchB();
  const c = await fetchC();
  return { a, b, c };
}

// 並列実行(速い)
async function parallel() {
  const [a, b, c] = await Promise.all([
    fetchA(),
    fetchB(),
    fetchC()
  ]);
  return { a, b, c };
}

// 一部だけ先に必要な場合
async function mixed() {
  const a = await fetchA();  // 先に必要
  const [b, c] = await Promise.all([fetchB(a), fetchC(a)]);
  return { a, b, c };
}

12. TypeScriptでの型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 戻り値の型
async function fetchData(): Promise<Data> {
  const response = await fetch('/api/data');
  return response.json();
}

// ジェネリック
async function fetchItem<T>(url: string): Promise<T> {
  const response = await fetch(url);
  return response.json() as T;
}

async/awaitのルール

ルール説明
await は async 内のみ通常の関数では使用不可
async は Promise を返す常に Promise でラップされる
await は Promise を待つ非 Promise でも動作
エラーは try-catchまたは .catch()

よくある間違い

  • forEach内でawaitを使って順番通りに実行されると思う
  • asyncを付けたら自動的に並列実行されると思う
  • awaitなしでPromiseを返して、呼び出し側で待つのを忘れる
  • async関数の戻り値が直接値だと思う(Promiseでラップされる)

関連エラー

参考リンク

JavaScript の他のエラー

最終更新: 2025-12-13