JavaScriptにおけるasync/await

JavaScriptにおけるasync/await

この記事ではJavaScriptにおけるasync/awaitについて説明します。

YouTube Video

JavaScriptにおけるasync/await

JavaScriptのasync(およびawait)は、非同期処理をより直感的で読みやすい形で書くための機能です。これを使うことで、従来のコールバック関数やPromiseチェーンの複雑さを軽減し、非同期処理を同期的なコードのように書けるようになります。

async関数

asyncは、関数を非同期関数として定義するために使います。async関数は、常にPromiseを返します。asyncが付けられた関数内では、awaitを使ってPromiseの結果が返ってくるまで待機することができます。

async関数の基本構文

1async function myAsyncFunction() {
2    // Write asynchronous processing here
3    return 'Result';  // Return a Promise
4}

この場合、myAsyncFunction()を呼び出すと、自動的にPromiseオブジェクトが返されます。Promiseが解決されると、その結果がreturnで返された値になります。

例: 基本的なasync関数

1async function greet() {
2    return 'Hello, World!';
3}
4
5greet().then((message) => {
6    console.log(message);  // Displays "Hello, World!"
7});

await

awaitは、Promiseが解決されるのを待つために使います。awaitを使うことで、Promiseが解決するまで処理を一時停止し、Promiseの結果を受け取ることができます。awaitは必ずasync関数の中でのみ使用可能です。

例: awaitの使い方

 1async function fetchData() {
 2    // Wait for the result of the Promise
 3    const data = await fetch('https://codesparklab.com/json/example.json');
 4    // Wait for the asynchronous operation to complete
 5    const jsonData = await data.json();
 6    // Retrieve and display the data
 7    console.log(jsonData);
 8}
 9
10fetchData();

上記の例では、fetch関数が返すPromiseをawaitで待ち、その結果を使ってさらに非同期処理を行っています。

async/awaitを使ったエラーハンドリング

async関数の中でエラーが発生すると、そのエラーはPromiseのrejectとして扱われます。try...catch文を使って、エラーハンドリングを行うことができます。

例: エラーハンドリング

 1async function fetchData() {
 2    try {
 3        // Invalid URL
 4        const data = await fetch('https://invalid.codesparklab.com/');
 5        const jsonData = await data.json();
 6        console.log(jsonData);
 7    } catch (error) {
 8        // Catch the error
 9        console.error('Failed to fetch data:', error);
10    }
11}
12
13fetchData();

try...catchブロックを使うことで、非同期処理中に発生するエラーを捕まえ、エラーが発生してもプログラムがクラッシュしないようにできます。

async/awaitのメリット

従来のPromiseチェーンと比較して、async/awaitは次のような利点があります。

  • 高い可読性
    • 非同期処理が同期処理のように記述できるため、ネストが深くなるPromiseチェーンやコールバックの煩雑さを避けられます。
  • 簡単なデバッグ
    • 同期的なコードに近いため、デバッグやエラーハンドリングが簡単になります。
  • 高い保守性
    • 非同期処理がシンプルに記述できるため、コードの変更や修正がしやすくなり、将来的なメンテナンス性が向上します。

例: Promiseチェーン vs async/await

Promiseチェーンを使ったコードとasync/awaitを使ったコードを比較してみましょう。

 1// Code using Promise chains
 2function fetchDataPromise() {
 3    fetch('https://codesparklab.com/json/example.json')
 4        .then((response) => response.json())
 5        .then((data) => {
 6            console.log(data);
 7        })
 8    .catch((error) => {
 9        console.error('Failed to fetch data:', error);
10    });
11}
12
13// Code using async/await
14async function fetchDataAsync() {
15    try {
16        const response = await fetch('https://codesparklab.com/json/example.json');
17        const data = await response.json();
18        console.log(data);
19    } catch (error) {
20        console.error('Failed to fetch data:', error);
21    }
22}

このように、async/awaitを使うと非同期処理が直線的に記述でき、より分かりやすいコードになります。

複数の非同期処理を同時に実行する

Promise.all()Promise.race()などとawaitを組み合わせることで、複数の非同期処理を同時に実行し、その結果をまとめて扱うこともできます。

Promise.all()

 1async function fetchMultipleData() {
 2    try {
 3        const [data1, data2] = await Promise.all([
 4            fetch('https://codesparklab.com/json/example1.json'),
 5            fetch('https://codesparklab.com/json/example2.json')
 6        ]);
 7        const jsonData1 = await data1.json();
 8        const jsonData2 = await data2.json();
 9        console.log(jsonData1);
10        console.log(jsonData2);
11    } catch (error) {
12        console.error('Failed to fetch data:', error);
13    }
14}
15
16fetchMultipleData();
  • Promise.all()は、複数のPromiseを同時に解決し、その結果を配列として返します。すべてのPromiseが解決されるまで待機し、どれか1つでも失敗すると全体が失敗とみなされます。

Promise.race()

 1async function fetchFastestData() {
 2    try {
 3        const fastestResponse = await Promise.race([
 4            fetch('https://codesparklab.com/json/example1.json'),
 5            fetch('https://codesparklab.com/json/example2.json')
 6        ]);
 7        const jsonData = await fastestResponse.json();
 8        console.log('Fastest data:', jsonData);
 9    } catch (error) {
10        console.error('Fetch error:', error);
11    }
12}
13
14fetchFastestData();
  • Promise.race()は、最初に解決または拒否されたPromiseの結果を返します。複数の非同期処理のうち、最も早く完了したものに反応したい場合に便利です。ただし、最初に失敗したPromiseがあると即座にcatchに入ります。

Promise.allSettled()

 1async function fetchWithAllSettled() {
 2    const results = await Promise.allSettled([
 3        // This URL will success
 4        fetch('https://codesparklab.com/json/example1.json'),
 5        // This URL will fail
 6        fetch('https://invalid.codesparklab.com/')
 7    ]);
 8
 9    results.forEach((result, index) => {
10        if (result.status === 'fulfilled') {
11            const url = result.value.url;
12            console.log(`Request ${index + 1} succeeded:`, url);
13        } else {
14            const reason = result.reason;
15            console.warn(`Request ${index + 1} failed:`, reason);
16        }
17    });
18}
19
20fetchWithAllSettled();
  • Promise.allSettled()は、成功・失敗に関わらず全ての結果を待ちます。それぞれの結果が{ status, value }または{ status, reason }の形式で返されるため、どれが成功し、どれが失敗したのかを確認できます。

Promise.any()

 1async function fetchAnySuccessful() {
 2    try {
 3        const firstSuccessful = await Promise.any([
 4            // This URL will fail
 5            fetch('https://invalid.codesparklab.com/'),
 6            // This URL will success
 7            fetch('https://codesparklab.com/json/example1.json')
 8        ]);
 9        const jsonData = await firstSuccessful.json();
10        console.log('First successful response:', jsonData);
11    } catch (error) {
12        console.error('All fetch requests failed:', error);
13    }
14}
15
16fetchAnySuccessful();
  • Promise.any()は、最初に成功したPromiseの結果だけを返します。すべてが失敗した場合のみ例外が投げられます。一部のAPIが不安定な環境で、成功するまでリトライ的に使うこともできます。

まとめ

  • async関数: 常にPromiseを返し、非同期処理を記述するために使います。
  • await: Promiseが解決されるまで待機し、結果を受け取るために使います。
  • エラーハンドリング: try...catchを使って、非同期処理中に発生するエラーを処理します。
  • 複数の非同期処理: Promise.all()などを使うことで、複数の非同期処理を同時に実行できます。

async/awaitは、非同期処理を扱う上で強力なツールなので、複雑な非同期ロジックをシンプルにするためにぜひ活用してください。

YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。

YouTube Video