Node.js async/await

Node.js では、async/awaitは非同期操作を処理するための構文糖衣です。

async/awaitPromise に基づいており、非同期コードを同期コードのように見せ、コードの可読性と保守性を大幅に向上させます。

asyncキーワードは、関数が非同期であることを宣言するために使用され、awaitキーワードは、Promise の解決(resolve)または拒否(reject)を待つために使用されます。

使用してasync/awaitコールバック地獄(callback hell)を回避し、エラー処理をより直感的にすることができます。

JavaScript はシングルスレッドであり、非同期タスク(setTimeout やネットワークリクエストなど)に遭遇すると、ブラウザー API に処理を任せ、完了後にコールバックをメッセージキューに入れます。

イベントループはコールスタックが空かどうかを絶えずチェックし、空であればキューからコールバックを取り出してコールスタックにプッシュして実行します。これにより、メインスレッドをブロックすることなく、非同期の結果を順番に処理できます。


基本構文

async 関数

任意の関数はasyncキーワードを追加することで非同期関数になることができます:

async function myFunction() {
  return "Hello World";
}

async関数は常に Promise を返します。戻り値が Promise でない場合、自動的に Promise にラップされます。

await 式

awaitでのみasync関数内部で使用でき、関数の実行を一時停止し、Promise の解決を待ってから、実行を継続して結果を返します:

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

エラー処理

try/catch 方式

処理async/awaitエラーの最も一般的な方法は使用することですtry/catch:

例

async function getUser() {
  try {
    const response = await fetch('https://api.example.com/user');
    const user = await response.json();
    return user;
  } catch (error) {
    console.error('Error fetching user:', error);
    throw error; // エラーを再スローすることもできます
  }
}

Promise を直接処理する

返された Promise を直接処理することもできます:

例

getUser()
  .then(user => console.log(user))
  .catch(error => console.error(error));

実際の応用例

複数の非同期操作を並列実行する

使用してPromise.all組み合わせてasync/await複数の非同期操作を並列実行できます:

例

async function fetchMultipleUrls(urls) {
  try {
    const requests = urls.map(url => fetch(url));
    const responses = await Promise.all(requests);
    const data = await Promise.all(responses.map(r => r.json()));
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
    throw error;
  }
}

データベース操作の例

例

async function getUserAndPosts(userId) {
  try {
    const user = await User.findById(userId);
    const posts = await Post.find({ userId });
    return { user, posts };
  } catch (error) {
    console.error('Database error:', error);
    throw error;
  }
}

ベストプラクティス

  1. 常にエラーを処理する:無視しないでくださいawait発生する可能性のあるエラーには、...を使用してtry/catch 或 .catch()処理します
  2. 不必要な await を避ける:結果を待つ必要がない場合は、Promise を直接返すことができます
  3. 並列処理を適切に使用する:複数の独立した非同期操作は並列実行する必要があります(使用してPromise.all)
  4. コードを明確に保つ:過度に深いasync/awaitネストを避け、必要に応じて関数を抽出します
  5. パフォーマンスへの影響に注意:各awaitが関数の実行を一時停止するため、ループ内では特に注意が必要です

よくある質問

async/await と Promise の関係

async/awaitPromise の上に構築された構文糖衣です。任意のasync関数は常に Promise を返し、任意のawaitの後には Promise を続けることができます。

なぜ私の async 関数は undefined を返すのですか?

これは、await前に使用することを忘れたreturn、または Promise が解決する前に関数が終了したことが原因かもしれません。

トップレベルで await を使用できますか?

ES モジュールでは(ファイルが.mjsで終わるか、またはpackage.json 中 "type": "module")、トップレベルで直接使用できますawait。CommonJS モジュールでは、...でラップする必要がありますasync関数の中に。

例

// ES モジュールでは
const data = await fetchData();
console.log(data);
その他の拡張