JavaScript の Promise、Async、Await についてのご説明

## 初め
Web開発では、非同期処理が一般的なプログラミング パラダイムになっています。 ネットワークリクエストの処理、ファイルの読み取りと書き込み、または遅延操作のいずれの場合でも、非同期処理はよりスムーズなユーザー エクスペリエンスを提供できます。 シングルスレッド言語である JavaScript の非同期処理の実装は特に重要です。 この記事では、JavaScript で非同期プログラミングを処理するための 3 つのコア技術、Promise、async、awaitを紹介します。 これらがどのように機能するか、使用する方法、そして実際のプロジェクトで効果的に適用する方法について詳しく説明します。

### 非同期処理とシングルスレッド
#### 非同期とは
```javascript
console.log(100)
setTimeout(function() {
	console.log(200)
}, 1000)
console.log(300)
```

```javascript
console.log(100)
alert(200)
console.log(300)
```
#### 非同期処理が必要になるのはどのような場合ですか?
1. 待機が発生する場合
2. 待機中はalertのようにプログラムをブロックすることを避けたい時
なので、「待機の場合」に非同期処理が必要

## 1. Promise
#### Promiseの基本
Promise は、非同期処理するための JavaScriptの重要な概念です。 これは、まだ完了していないが、将来完了することが期待される操作を表します。 Promise を使用すると、いわゆる「コールバック地獄」、つまりネストされたコールバック関数の複数の層を回避でき、コードがより明確になり、保守が容易になります。
#### コード例: 基本的な Promise の作成
```javascript
let promise = new Promise(function(resolve, reject) {
  // 非同期処理コード
  setTimeout(() => {
    resolve("操作成功");
  }, 1000);
});

promise.then((value) => {
  console.log(value); // output: 操作成功
});
```

#### Promiseのステータス
Promise には 3 つのステータスがあります

- pending(待機): 成功でも失敗でもない初期状態。
- fulfilled（成功した）: 操作が正常に完了したこと。
- rejected（拒否された）: 操作が失敗したこと。

#### コード例: さまざまなステータスを示すPromise
```javascript
let fulfilledPromise = Promise.resolve('成功');
let rejectedPromise = Promise.reject('失敗');

fulfilledPromise.then(value => console.log(value)); // output: 成功
rejectedPromise.catch(error => console.log(error)); // output: 失敗
```

#### メソッドチェーンとエラー処理
Promise のもう 1 つの利点は、.then() メソッドと .catch() メソッドを連鎖させることで複雑な非同期プロセスを処理できることです。

#### コード例: メソッドチェーンとエラー処理
```javascript
new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 1000);
})
.then(result => {
    console.log(result); // output: 1
    return result * 2;
})
.then(result => {
    console.log(result); // output: 2
    return result * 3;
})
.then(result => {
    console.log(result); // output: 6
    return result * 4;
})
.catch(error => {
    console.log('エラーがありました：', error);
});
```

#### 実用化
実際のプロジェクトでは、Promise を使用して、ネットワーク リクエストやファイル処理などの非同期操作が管理しやすくなります。 Promise を使用すると、より読みやすく保守しやすいコードを作成できます。

## 2.　Async/Await

async と await は Promise に基づいて構築された高レベルの抽象化であり、非同期コードの書き込みと読み取りを同期コードのスタイルに近づけます。
#### Async関数
関数宣言の前に async キーワードを指定することで、任意の関数を Promise を返す非同期関数に変換できます。 これは、 .then() と .catch() を使用して結果を処理できることを意味します。
#### コード例: 非同期関数を作成する

```javascript
async function asyncFunction() {
  return "非同期処理完了";
}

asyncFunction().then(value => console.log(value)); // output：非同期処理完了

```

#### Await キーワード
await キーワードは、非同期関数内でのみ使用できます。 非同期関数の実行を一時停止し、Promise が解決される (解決する) まで待機してから、Promise の値を使用して関数の実行を続行できます。

#### コード例: 非同期関数での await の使用
```javascript
async function asyncFunction() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("完成"), 1000)
  });

  let result = await promise; // promiseが解決できるまで待ちます。(resolve)
  console.log(result); // "完成"
}

asyncFunction();

```

#### エラー処理
async/await では、従来の try...catch ステートメントを通じてエラー処理を実装できるため、非同期コードでのエラー処理がより直観的になります。

#### コード例: try...catch を使用してエラーを処理する
```javascript
async function asyncFunction() {
  try {
    let response = await fetch('http://example.com');
    let data = await response.json();
    // データを処理する
  } catch (error) {
    console.log('エラーが発生しました：', error);
  }
}

asyncFunction();

```

#### 実用化
実際のアプリケーションでは、async と await を使用すると、特に連続して実行される複数の非同期処理が含まれる場合に、複雑な非同期ロジックの処理が容易になります。

## 3. Promise と Async/Await の比較

多くの場合、async/await はより簡潔なコードを提供できますが、Promise には独自の利点もあります。 たとえば、複数の並列非同期操作を処理する場合は、多くの場合、Promise.all() の方が適しています。 Promise または async/await のどちらを使用するかは、通常、特定のアプリケーション シナリオと個人の好みによって決まります。

### 結論
Promise、async、await を理解して習得することは、有能な Frontend 開発者になるための重要なステップです。 これらのツールは、複雑な非同期操作を処理する柔軟な方法を提供します。 すべての Frontend 開発者は、コードの可読性と保守性を向上させるために、プロジェクトでこれらの概念を実践することをお勧めします。