MeWrite Docs

SyntaxError: await is only valid in async functions

JavaScriptでasync関数外でawaitを使用した場合のエラー

概要

await is only valid in async functions は、await キーワードを async 関数の外で使用した場合に発生するエラーです。非同期処理を扱う際によく遭遇します。

エラーメッセージ

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

原因

1. 通常の関数でawaitを使用

1
2
3
4
5
// NG: async がない
function fetchData() {
  const response = await fetch('/api/data');  // SyntaxError
  return response.json();
}

2. コールバック関数でawaitを使用

1
2
3
4
5
// NG: コールバックにasyncがない
const items = [1, 2, 3];
items.forEach(item => {
  const result = await processItem(item);  // SyntaxError
});

3. アロー関数でasyncを忘れた

1
2
3
4
5
// NG: アロー関数にasyncがない
const getData = () => {
  const data = await fetch('/api');  // SyntaxError
  return data;
};

解決策

1. 関数にasyncを追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// OK: asyncを追加
async function fetchData() {
  const response = await fetch('/api/data');
  return response.json();
}

// アロー関数の場合
const fetchData = async () => {
  const response = await fetch('/api/data');
  return response.json();
};

2. コールバック関数にasyncを追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// NG: forEachのコールバック
items.forEach(item => {
  const result = await processItem(item);  // SyntaxError
});

// OK: コールバックにasync
items.forEach(async item => {
  const result = await processItem(item);
});

// 注意: forEach + asyncは順序が保証されない
// 順序が必要な場合はfor...ofを使用
async function processAll(items) {
  for (const item of items) {
    const result = await processItem(item);
    console.log(result);
  }
}

3. Promise.allで並列処理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// OK: 並列処理
async function processAll(items) {
  const results = await Promise.all(
    items.map(item => processItem(item))
  );
  return results;
}

// mapのコールバックにasyncを使う場合
async function processAll(items) {
  const results = await Promise.all(
    items.map(async item => {
      const processed = await processItem(item);
      return processed;
    })
  );
  return results;
}

4. トップレベルawait(ESモジュール)

1
2
3
4
5
6
7
8
// package.jsonで "type": "module" を設定

// OK: ESモジュールのトップレベル
const response = await fetch('/api/data');
const data = await response.json();
console.log(data);

// または .mjs 拡張子を使用

5. 即時実行関数(IIFE)を使用

1
2
3
4
5
6
// 通常のスクリプトでトップレベルawaitが使えない場合
(async () => {
  const response = await fetch('/api/data');
  const data = await response.json();
  console.log(data);
})();

よくあるパターン

クラスメソッド

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class ApiClient {
  // NG: asyncがない
  fetchUser(id) {
    const response = await fetch(`/users/${id}`);  // SyntaxError
    return response.json();
  }

  // OK: asyncを追加
  async fetchUser(id) {
    const response = await fetch(`/users/${id}`);
    return response.json();
  }
}

イベントハンドラ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// NG: ハンドラにasyncがない
button.addEventListener('click', () => {
  const data = await fetchData();  // SyntaxError
});

// OK: asyncを追加
button.addEventListener('click', async () => {
  const data = await fetchData();
  console.log(data);
});

Reactコンポーネント

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// NG: useEffectのコールバックは直接asyncにできない
useEffect(() => {
  const data = await fetchData();  // SyntaxError
}, []);

// OK: 内部で非同期関数を定義
useEffect(() => {
  const loadData = async () => {
    const data = await fetchData();
    setData(data);
  };
  loadData();
}, []);

// OK: IIFEパターン
useEffect(() => {
  (async () => {
    const data = await fetchData();
    setData(data);
  })();
}, []);

Express.js ルート

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// NG: asyncがない
app.get('/api/users', (req, res) => {
  const users = await User.findAll();  // SyntaxError
  res.json(users);
});

// OK: asyncを追加
app.get('/api/users', async (req, res) => {
  try {
    const users = await User.findAll();
    res.json(users);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

async/awaitとthen/catchの使い分け

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// async/await
async function fetchData() {
  try {
    const response = await fetch('/api');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error(error);
    throw error;
  }
}

// then/catch(asyncなしで使える)
function fetchData() {
  return fetch('/api')
    .then(response => response.json())
    .catch(error => {
      console.error(error);
      throw error;
    });
}

注意点

forEachでは完了を待てない

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// NG: 処理完了を待てない
async function processAll(items) {
  items.forEach(async item => {
    await processItem(item);
  });
  console.log('完了');  // 処理完了前に実行される
}

// OK: for...ofを使用
async function processAll(items) {
  for (const item of items) {
    await processItem(item);
  }
  console.log('完了');  // 全処理完了後に実行
}

関連エラー

関連エラー

JavaScript の他のエラー

最終更新: 2025-12-23