JavaScriptでのイベントループ、コールバック、プロミス、非同期/待機について理解する

提供:Dev Guides
移動先:案内検索

著者はCOVID-19救済基金を選択し、 Write forDOnationsプログラムの一環として寄付を受け取りました。

序章

インターネットの初期には、WebサイトはHTMLページの静的データで構成されていました。 しかし、Webアプリケーションがよりインタラクティブで動的になった今、APIデータを取得するための外部ネットワーク要求を行うなどの集中的な操作を行うことがますます必要になっています。 JavaScriptでこれらの操作を処理するには、開発者は非同期プログラミング手法を使用する必要があります。

JavaScriptはシングルスレッドプログラミング言語であり、同期実行モデルが次々に操作を処理するため、一度に処理できるのは1つのステートメントのみです。 ただし、APIからのデータの要求などのアクションは、要求されるデータのサイズ、ネットワーク接続の速度、およびその他の要因によっては、不確定な時間がかかる場合があります。 API呼び出しが同期的に実行された場合、ブラウザは、その操作が完了するまで、スクロールやボタンのクリックなどのユーザー入力を処理できません。 これは、ブロッキングとして知られています。

ブロッキング動作を防ぐために、ブラウザ環境には、JavaScriptがアクセスできる非同期の多くのWeb APIがあります。つまり、それらは順番にではなく、他の操作と並行して実行できます。 これは、非同期操作の処理中にユーザーがブラウザーを通常どおり使用し続けることができるため便利です。

JavaScript開発者は、非同期Web APIを操作し、それらの操作の応答またはエラーを処理する方法を知っている必要があります。 この記事では、イベントループ、コールバックを介して非同期動作を処理する元の方法、更新された ECMAScript 2015 のpromiseの追加、およびasync/awaitを使用する最新の方法について学習します。

注:この記事は、ブラウザー環境でのクライアント側のJavaScriptに焦点を当てています。 同じ概念がNode.js環境でも一般的に当てはまりますが、Node.jsはブラウザーの WebAPIではなく独自のC++APIを使用します。 Node.jsでの非同期プログラミングの詳細については、Node.jsで非同期コードを作成する方法を確認してください。


イベントループ

このセクションでは、JavaScriptがイベントループを使用して非同期コードを処理する方法について説明します。 まず、動作中のイベントループのデモンストレーションを実行し、次にイベントループの2つの要素であるスタックとキューについて説明します。

非同期WebAPIを使用しないJavaScriptコードは、同期的に1つずつ順番に実行されます。 これは、それぞれがconsoleに番号を出力する3つの関数を呼び出すこのサンプルコードによって示されます。

// Define three example functions
function first() {
  console.log(1)
}

function second() {
  console.log(2)
}

function third() {
  console.log(3)
}

このコードでは、console.log()で数値を出力する3つの関数を定義します。

次に、関数への呼び出しを記述します。

// Execute the functions
first()
second()
third()

出力は、関数が呼び出された順序(first()second()third())に基づきます。

Output1
2
3

非同期WebAPIを使用すると、ルールがより複雑になります。 これをテストできる組み込みAPIはsetTimeoutで、タイマーを設定し、指定された時間が経過するとアクションを実行します。 setTimeoutは非同期である必要があります。そうしないと、待機中にブラウザー全体がフリーズしたままになり、ユーザーエクスペリエンスが低下します。

setTimeoutsecond関数に追加して、非同期要求をシミュレートします。

// Define three example functions, but one of them contains asynchronous code
function first() {
  console.log(1)
}

function second() {
  setTimeout(() => {
    console.log(2)
  }, 0)
}

function third() {
  console.log(3)
}

setTimeoutは、2つの引数を取ります。非同期で実行される関数と、その関数を呼び出す前に待機する時間です。 このコードでは、console.logを無名関数でラップし、setTimeoutに渡してから、0ミリ秒後に実行するように関数を設定しました。

前に行ったように、関数を呼び出します。

// Execute the functions
first()
second()
third()

setTimeout0に設定すると、これら3つの関数を実行しても、番号が順番に出力されることが予想されます。 ただし、非同期であるため、タイムアウトのある関数は最後に出力されます。

Output1
3
2

タイムアウトを0秒に設定しても5分に設定しても、違いはありません。非同期コードによって呼び出されるconsole.logは、同期トップレベル関数の後に実行されます。 これは、JavaScriptホスト環境(この場合はブラウザー)がイベントループと呼ばれる概念を使用して、同時実行または並列イベントを処理するために発生します。 JavaScriptは一度に1つのステートメントしか実行できないため、どの特定のステートメントをいつ実行するかをイベントループに通知する必要があります。 イベントループは、スタックキューの概念でこれを処理します。

スタック

スタック、または呼び出しスタックは、現在実行されている関数の状態を保持します。 スタックの概念に慣れていない場合は、「後入れ先出し」(LIFO)プロパティを持つ配列として想像できます。つまり、最後からアイテムを追加または削除することしかできません。スタック。 JavaScriptは、スタック内の現在の frame (または特定の環境での関数呼び出し)を実行し、それを削除して次のフレームに移動します。

同期コードのみを含む例の場合、ブラウザは次の順序で実行を処理します。

  • first()をスタックに追加し、first()を実行して1をコンソールに記録し、スタックからfirst()を削除します。
  • second()をスタックに追加し、second()を実行して2をコンソールに記録し、スタックからsecond()を削除します。
  • third()をスタックに追加し、third()を実行して3をコンソールに記録し、スタックからthird()を削除します。

setTimoutの2番目の例は、次のようになります。

  • first()をスタックに追加し、first()を実行して1をコンソールに記録し、スタックからfirst()を削除します。
  • second()をスタックに追加し、second()を実行します。 スタックにsetTimeout()を追加し、タイマーを開始して無名関数をキューに追加するsetTimeout()Web APIを実行し、スタックからsetTimeout()を削除します。
  • スタックからsecond()を削除します。
  • third()をスタックに追加し、third()を実行して3をコンソールに記録し、スタックからthird()を削除します。
  • イベントループは、保留中のメッセージがないかキューをチェックし、setTimeout()から無名関数を見つけ、2をコンソールに記録するスタックに関数を追加し、スタックから削除します。

非同期WebAPIであるsetTimeoutを使用して、このチュートリアルで次に説明するキューの概念を紹介します。

キューは、メッセージキューまたはタスクキューとも呼ばれ、機能の待機領域です。 コールスタックが空の場合は常に、イベントループは、最も古いメッセージから開始して、待機中のメッセージがないかキューをチェックします。 見つかったら、それをスタックに追加し、メッセージ内の関数を実行します。

setTimeoutの例では、タイマーが0秒に設定されているため、匿名関数は残りのトップレベル実行の直後に実行されます。 タイマーは、コードが正確に0秒または指定された時間で実行されることを意味するのではなく、その時間内に匿名関数をキューに追加することを覚えておくことが重要です。 このキューシステムが存在するのは、タイマーの終了時にタイマーが匿名関数をスタックに直接追加すると、現在実行中の関数が中断され、意図しない予期しない影響が生じる可能性があるためです。

注:promiseを処理するジョブキューまたはマイクロタスクキューと呼ばれる別のキューもあります。 promiseのようなマイクロタスクは、setTimeoutのようなマクロタスクよりも高い優先度で処理されます。


これで、イベントループがスタックとキューを使用してコードの実行順序を処理する方法がわかりました。 次のタスクは、コードの実行順序を制御する方法を理解することです。 これを行うには、最初に、非同期コードがイベントループによって正しく処理されるようにする元の方法であるコールバック関数について学習します。

コールバック関数

setTimeoutの例では、タイムアウトのある関数は、メインのトップレベルの実行コンテキストのすべての後に実行されました。 ただし、third関数などの関数のいずれかがタイムアウト後に実行されるようにする場合は、非同期コーディング方式を使用する必要があります。 ここでのタイムアウトは、データを含む非同期API呼び出しを表すことができます。 API呼び出しからのデータを処理したいが、データが最初に返されることを確認する必要があります。

この問題に対処するための元の解決策は、コールバック関数を使用することです。 コールバック関数には特別な構文はありません。 これらは、引数として別の関数に渡された関数にすぎません。 別の関数を引数とする関数を高階関数と呼びます。 この定義によれば、引数として渡された場合、任意の関数がコールバック関数になる可能性があります。 コールバックは本質的に非同期ではありませんが、非同期の目的で使用できます。

高階関数とコールバックの構文コードの例を次に示します。

// A function
function fn() {
  console.log('Just a function')
}

// A function that takes another function as an argument
function higherOrderFunction(callback) {
  // When you call a function that is passed as an argument, it is referred to as a callback
  callback()
}

// Passing a function
higherOrderFunction(fn)

このコードでは、関数fnを定義し、関数callbackを引数として取る関数higherOrderFunctionを定義し、fnをコールバックとして渡します。 higherOrderFunction

このコードを実行すると、次のようになります。

OutputJust a function

firstsecond、およびthird機能にsetTimeoutを使用して戻りましょう。 これはあなたがこれまでに持っているものです:

function first() {
  console.log(1)
}

function second() {
  setTimeout(() => {
    console.log(2)
  }, 0)
}

function third() {
  console.log(3)
}

タスクは、third関数を取得して、second関数の非同期アクションが完了するまで常に実行を遅らせることです。 これがコールバックの出番です。 実行のトップレベルでfirstsecond、およびthirdを実行する代わりに、third関数を引数としてsecondsecond関数は、非同期アクションが完了した後にコールバックを実行します。

コールバックが適用された3つの関数は次のとおりです。

// Define three functions
function first() {
  console.log(1)
}

function second(callback) {
  setTimeout(() => {
    console.log(2)

    // Execute the callback function
    callback()
  }, 0)
}

function third() {
  console.log(3)
}

ここで、firstsecondを実行し、thirdを引数としてsecondに渡します。

first()
second(third)

このコードブロックを実行すると、次の出力が表示されます。

Output1
2
3

最初に1が印刷され、タイマーが完了すると(この場合、0秒ですが、任意の量に変更できます)、2、次に3が印刷されます。 関数をコールバックとして渡すことにより、非同期Web API(setTimeout)が完了するまで関数の実行を正常に遅らせることができます。

ここで重要なポイントは、コールバック関数が非同期ではないことです。setTimeoutは、非同期タスクの処理を担当する非同期WebAPIです。 コールバックを使用すると、非同期タスクが完了したときに通知を受け、タスクの成功または失敗を処理できます。

コールバックを使用して非同期タスクを処理する方法を学習したので、次のセクションでは、あまりにも多くのコールバックをネストして「運命のピラミッド」を作成する問題について説明します。

ネストされたコールバックと運命のピラミッド

コールバック関数は、別の関数が完了してデータを返すまで、関数の実行を遅らせるための効果的な方法です。 ただし、コールバックはネストされているため、相互に依存する連続した非同期リクエストが多数ある場合、コードが乱雑になる可能性があります。 これは、JavaScript開発者にとって初期の大きなフラストレーションであり、その結果、ネストされたコールバックを含むコードは、「運命のピラミッド」または「コールバック地獄」と呼ばれることがよくあります。

ネストされたコールバックのデモンストレーションは次のとおりです。

function pyramidOfDoom() {
  setTimeout(() => {
    console.log(1)
    setTimeout(() => {
      console.log(2)
      setTimeout(() => {
        console.log(3)
      }, 500)
    }, 2000)
  }, 1000)
}

このコードでは、新しいsetTimeoutはそれぞれ高階関数内にネストされ、より深いコールバックのピラミッド形状を作成します。 このコードを実行すると、次のようになります。

Output1
2
3

実際には、実際の非同期コードでは、これははるかに複雑になる可能性があります。 ほとんどの場合、非同期コードでエラー処理を実行してから、各応答から次の要求にデータを渡す必要があります。 コールバックを使用してこれを行うと、コードの読み取りと保守が困難になります。

これは、より現実的な「運命のピラミッド」の実行可能な例です。

// Example asynchronous function
function asynchronousRequest(args, callback) {
  // Throw an error if no arguments are passed
  if (!args) {
    return callback(new Error('Whoa! Something went wrong.'))
  } else {
    return setTimeout(
      // Just adding in a random number so it seems like the contrived asynchronous function
      // returned different data
      () => callback(null, {body: args + ' ' + Math.floor(Math.random() * 10)}),
      500,
    )
  }
}

// Nested asynchronous requests
function callbackHell() {
  asynchronousRequest('First', function first(error, response) {
    if (error) {
      console.log(error)
      return
    }
    console.log(response.body)
    asynchronousRequest('Second', function second(error, response) {
      if (error) {
        console.log(error)
        return
      }
      console.log(response.body)
      asynchronousRequest(null, function third(error, response) {
        if (error) {
          console.log(error)
          return
        }
        console.log(response.body)
      })
    })
  })
}

// Execute 
callbackHell()

このコードでは、すべての関数が可能なresponseと可能なerrorを考慮に入れる必要があり、関数callbackHellが視覚的に混乱します。

このコードを実行すると、次のようになります。

Output
First 9
Second 3
Error: Whoa! Something went wrong.
    at asynchronousRequest (<anonymous>:4:21)
    at second (<anonymous>:29:7)
    at <anonymous>:9:13

非同期コードを処理するこの方法に従うのは困難です。 その結果、promisesの概念がES6に導入されました。 これが次のセクションの焦点です。

約束

promise は、非同期機能の完了を表します。 将来的に値を返す可能性のあるオブジェクトです。 コールバック関数と同じ基本的な目標を達成しますが、多くの追加機能とより読みやすい構文を備えています。 JavaScript開発者は、プロミスを作成するよりも多くの時間を費やす可能性があります。これは、通常、開発者が消費するプロミスを返す非同期WebAPIであるためです。 このチュートリアルでは、両方を行う方法を説明します。

約束を作成する

new Promise構文を使用してpromiseを初期化でき、関数を使用して初期化する必要があります。 promiseに渡される関数には、resolveおよびrejectパラメーターがあります。 resolve関数とreject関数は、それぞれ操作の成功と失敗を処理します。

約束を宣言するには、次の行を記述します。

// Initialize a promise
const promise = new Promise((resolve, reject) => {})

この状態で初期化されたpromiseをWebブラウザーのコンソールで調べると、pendingステータスとundefined値があることがわかります。

Output__proto__: Promise
[[PromiseStatus]]: "pending"
[[PromiseValue]]: undefined

これまでのところ、約束のために何も設定されていないので、それは永遠にpending状態でそこに座るでしょう。 約束をテストするために最初にできることは、値でそれを解決することによって約束を果たすことです。

const promise = new Promise((resolve, reject) => {
  resolve('We did it!')
})

これで、Promiseを調べると、ステータスがfulfilledであり、valueresolveに渡した値に設定されていることがわかります。

Output__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: "We did it!"

このセクションの冒頭で述べたように、promiseは値を返す可能性のあるオブジェクトです。 正常に実行されると、valueundefinedからデータが入力されます。

約束には、保留中、履行済み、および拒否の3つの状態があります。

  • 保留中-解決または拒否される前の初期状態
  • Fulfilled -正常な操作、promiseは解決されました
  • 却下-操作に失敗しました。Promiseは却下されました

履行または拒否された後、約束は解決されます。

これで、Promiseがどのように作成されるかがわかったので、開発者がこれらのPromiseをどのように使用するかを見てみましょう。

約束を消費する

前のセクションの約束は値で満たされましたが、値にアクセスできるようにする必要もあります。 Promiseにはthenというメソッドがあり、コード内でPromiseがresolveに達した後に実行されます。 thenは、promiseの値をパラメーターとして返します。

これは、サンプルpromiseのvalueを返してログに記録する方法です。

promise.then((response) => {
  console.log(response)
})

あなたが作成した約束には、We did it!PromiseValueがありました。 この値は、responseとして匿名関数に渡される値です。

OutputWe did it!

これまでのところ、作成した例には非同期Web APIは含まれていませんでした。これは、ネイティブJavaScript Promiseを作成、解決、および使用する方法のみを説明したものです。 setTimeoutを使用して、非同期リクエストをテストできます。

次のコードは、非同期リクエストから返されるデータをpromiseとしてシミュレートします。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve('Resolving an asynchronous request!'), 2000)
})

// Log the result
promise.then((response) => {
  console.log(response)
})

then構文を使用すると、2000ミリ秒後にsetTimeout操作が完了した場合にのみ、responseがログに記録されます。 これはすべて、コールバックをネストせずに実行されます。

2秒後、promise値が解決され、thenにログインします。

OutputResolving an asynchronous request!

Promiseをチェーン化して、データを複数の非同期操作に渡すこともできます。 thenに値が返された場合、前のthenの戻り値を満たす別のthenを追加できます。

// Chain a promise
promise
  .then((firstResponse) => {
    // Return a new value for the next then
    return firstResponse + ' And chaining!'
  })
  .then((secondResponse) => {
    console.log(secondResponse)
  })

2番目のthenで満たされた応答は、戻り値をログに記録します。

OutputResolving an asynchronous request! And chaining!

thenは連鎖できるため、promiseの消費は、ネストする必要がないため、コールバックよりも同期的に見えるようになります。 これにより、より読みやすいコードが可能になり、保守と検証が容易になります。

エラー処理

これまでのところ、resolveが成功した場合にのみ、Promiseを処理しました。これにより、Promiseはfulfilled状態になります。 ただし、非同期リクエストでは、APIがダウンしている場合や、不正な形式または不正なリクエストが送信された場合に、エラーを処理する必要があることがよくあります。 約束は両方の場合を処理できるはずです。 このセクションでは、promiseの作成と使用の成功とエラーの両方のケースをテストする関数を作成します。

このgetUsers関数は、promiseにフラグを渡し、promiseを返します。

function getUsers(onSuccess) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // Handle resolve and reject in the asynchronous API
    }, 1000)
  })
}

onSuccesstrueの場合、タイムアウトが一部のデータで満たされるようにコードを設定します。 falseの場合、関数は次のエラーで拒否します。

function getUsers(onSuccess) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // Handle resolve and reject in the asynchronous API
      if (onSuccess) {
        resolve([
          {id: 1, name: 'Jerry'},
          {id: 2, name: 'Elaine'},
          {id: 3, name: 'George'},
        ])
      } else {
        reject('Failed to fetch data!')
      }
    }, 1000)
  })
}

正常な結果を得るには、サンプルユーザーデータを表すJavaScriptオブジェクトを返します。

エラーを処理するには、catchインスタンスメソッドを使用します。 これにより、errorをパラメーターとして使用した失敗コールバックが提供されます。

onSuccessfalseに設定して、getUserコマンドを実行します。成功した場合は、thenメソッドを使用し、エラーの場合はcatchメソッドを使用します。 :

// Run the getUsers function with the false flag to trigger an error
getUsers(false)
  .then((response) => {
    console.log(response)
  })
  .catch((error) => {
    console.error(error)
  })

エラーがトリガーされたため、thenはスキップされ、catchがエラーを処理します。

OutputFailed to fetch data!

フラグとresolveを切り替えると、catchは無視され、代わりにデータが返されます。

// Run the getUsers function with the true flag to resolve successfully
getUsers(true)
  .then((response) => {
    console.log(response)
  })
  .catch((error) => {
    console.error(error)
  })

これにより、ユーザーデータが生成されます。

Output(3) [{…}, {…}, {…}]
0: {id: 1, name: "Jerry"}
1: {id: 2, name: "Elaine"}
3: {id: 3, name: "George"}

参考までに、Promiseオブジェクトのハンドラーメソッドの表を次に示します。

方法 説明
then() resolveを処理します。 promiseを返し、onFulfilled関数を非同期で呼び出します
catch() rejectを処理します。 promiseを返し、onRejected関数を非同期で呼び出します
finally() 約束が決まったときに呼び出されます。 promiseを返し、onFinally関数を非同期で呼び出します

これまで非同期環境で作業したことがない新しい開発者と経験豊富なプログラマーの両方にとって、約束は混乱を招く可能性があります。 ただし、前述のように、プロミスを作成するよりも消費する方がはるかに一般的です。 通常、ブラウザのWeb APIまたはサードパーティのライブラリが約束を提供し、それを使用するだけで済みます。

最後のpromiseセクションでは、このチュートリアルで、promiseを返すWeb APIの一般的なユースケースを引用します: FetchAPI

PromisesでのFetchAPIの使用

promiseを返す最も便利で頻繁に使用されるWebAPIの1つは、Fetch APIです。これにより、ネットワークを介して非同期リソース要求を行うことができます。 fetchは2つの部分からなるプロセスであるため、thenをチェーンする必要があります。 この例は、GitHub APIをヒットしてユーザーのデータをフェッチすると同時に、潜在的なエラーを処理する方法を示しています。

// Fetch a user from the GitHub API
fetch('https://api.github.com/users/octocat')
  .then((response) => {
    return response.json()
  })
  .then((data) => {
    console.log(data)
  })
  .catch((error) => {
    console.error(error)
  })

fetchリクエストはhttps://api.github.com/users/octocatURLに送信され、非同期で応答を待ちます。 最初のthenは、応答を JSONデータとしてフォーマットする無名関数に応答を渡し、次に、データをコンソールに記録する2番目のthenにJSONを渡します。 catchステートメントは、エラーをコンソールに記録します。

このコードを実行すると、次のようになります。

Outputlogin: "octocat",
id: 583231,
avatar_url: "https://avatars3.githubusercontent.com/u/583231?v=4"
blog: "https://github.blog"
company: "@github"
followers: 3203
...

これは、https://api.github.com/users/octocatから要求されたデータであり、JSON形式でレンダリングされます。

チュートリアルのこのセクションでは、promiseに非同期コードを処理するための多くの改善が組み込まれていることを示しました。 ただし、thenを使用して非同期アクションを処理するのは、コールバックのピラミッドよりも簡単ですが、一部の開発者は、非同期コードを記述する同期形式を好む場合があります。 このニーズに対応するために、 ECMAScript 2016(ES7)は、async関数とawaitキーワードを導入して、promiseの操作を容易にしました。

async/awaitを使用した非同期関数

非同期関数を使用すると、同期しているように見える方法で非同期コードを処理できます。 async関数は、内部でpromiseを使用しますが、より伝統的なJavaScript構文を使用します。 このセクションでは、この構文の例を試してみます。

関数の前にasyncキーワードを追加すると、async関数を作成できます。

// Create an async function
async function getUser() {
  return {}
}

この関数はまだ非同期を処理していませんが、従来の関数とは動作が異なります。 関数を実行すると、戻り値の代わりにPromiseStatusPromiseValueのpromiseが返されることがわかります。

getUser関数への呼び出しをログに記録して、これを試してください。

console.log(getUser())

これにより、次のようになります。

Output__proto__: Promise
[[PromiseStatus]]: "fulfilled"
[[PromiseValue]]: Object

これは、promiseを処理するのと同じ方法で、async関数をthenで処理できることを意味します。 次のコードでこれを試してください。

getUser().then((response) => console.log(response))

このgetUserの呼び出しは、戻り値を匿名関数に渡し、匿名関数は値をコンソールに記録します。

このプログラムを実行すると、次のメッセージが表示されます。

Output{}

async関数は、await演算子を使用してその中で呼び出されたpromiseを処理できます。 awaitは、async関数内で使用でき、promiseが解決するまで待機してから、指定されたコードを実行します。

この知識があれば、次のようにasync / awaitを使用して、前のセクションのフェッチ要求を書き換えることができます。

// Handle fetch with async/await
async function getUser() {
  const response = await fetch('https://api.github.com/users/octocat')
  const data = await response.json()

  console.log(data)
}

// Execute async function
getUser()

ここでのawait演算子は、リクエストがデータを入力する前にdataがログに記録されないようにします。

これで、thenを使用しなくても、datagetUser関数内で処理できるようになりました。 これは、ロギングdataの出力です。

Outputlogin: "octocat",
id: 583231,
avatar_url: "https://avatars3.githubusercontent.com/u/583231?v=4"
blog: "https://github.blog"
company: "@github"
followers: 3203
...

注:多くの環境では、awaitを使用するにはasyncが必要ですが、一部の新しいバージョンのブラウザーとノードでは、トップレベルのawaitを使用できます。これにより、awaitをラップする非同期関数の作成をバイパスできます。


最後に、非同期関数内で実行されたpromiseを処理しているため、関数内でエラーを処理することもできます。 catchメソッドをthenで使用する代わりに、 try /catchパターンを使用して例外を処理します。

次の強調表示されたコードを追加します。

// Handling success and errors with async/await
async function getUser() {
  try {
    // Handle success in try
    const response = await fetch('https://api.github.com/users/octocat')
    const data = await response.json()

    console.log(data)
  } catch (error) {
    // Handle error in catch
    console.error(error)
  }
}

エラーを受信した場合、プログラムはcatchブロックにスキップし、そのエラーをコンソールに記録します。

最新の非同期JavaScriptコードは、ほとんどの場合async / await構文で処理されますが、特にPromiseは処理できない追加機能に対応しているため、Promiseがどのように機能するかについて実用的な知識を持っていることが重要です。 async / awaitを使用します。たとえば、promiseを Promise.all()と組み合わせます。

ノート: async/await can be reproduced by using ジェネレーターとプロミスの組み合わせ to add more flexibility to your code. To learn more, check out our JavaScriptのジェネレーターを理解する tutorial.


結論

Web APIはデータを非同期で提供することが多いため、非同期アクションの結果を処理する方法を学ぶことは、JavaScript開発者であるための重要な部分です。 この記事では、ホスト環境がイベントループを使用して、スタックおよびキューでコードの実行順序を処理する方法を学習しました。 また、コールバック、promise、およびasync / await構文を使用して、非同期イベントの成功または失敗を処理する3つの方法の例を試しました。 最後に、FetchWebAPIを使用して非同期アクションを処理しました。

ブラウザが並列イベントを処理する方法の詳細については、MozillaDeveloperNetworkの同時実行モデルとイベントループを参照してください。 JavaScriptについて詳しく知りたい場合は、JavaScriptでコーディングする方法シリーズに戻ってください。