Observableとasync/awaitの違いを理解する

# **Observableとasync/awaitの違いを理解する**

## **はじめに**
AngularやTypeScriptでは、非同期処理を扱う際に主に以下の2つのパターンが使われます：
1. **Observable（RxJS）**  
2. **async/await（Promiseベース）**

両者は非同期処理を扱うための方法ですが、それぞれに特徴や適した場面があります。この記事では、両者の基本的な使い方と、それぞれを使った非同期処理の実装例を解説します。

---

## **目次**
1. Observableの基本
2. async/awaitの基本
3. Observableとasync/awaitの実践例
4. どちらを使うべきか？場面ごとの選択

---

## **1. Observableの基本**
Observableは**RxJSライブラリ**によって提供される非同期処理のツールです。特徴として、**ストリーム**（複数の値を時間に沿って配信）を扱える点があります。

### **基本的な使い方**
```typescript
import { Observable } from 'rxjs';

const observable = new Observable<number>((observer) => {
  observer.next(1);  // 値を送信
  observer.next(2);
  observer.complete(); // 完了
});

observable.subscribe({
  next: (value) => console.log(value), // 値を受け取る
  complete: () => console.log('Completed'), // 完了時に呼ばれる
});
```

---

## **2. async/awaitの基本**
`async/await`は、Promiseを使って非同期処理を直感的に記述できる方法です。一度に**単一の値**を扱います。

### **基本的な使い方**
```typescript
const asyncFunction = async (): Promise<number> => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(42), 1000);
  });
};

(async () => {
  const result = await asyncFunction();
  console.log(result); // 42
})();
```

---

## **3. Observableとasync/awaitの実践例**

以下では、APIからデータを取得するシナリオで、Observableとasync/awaitを使った例を比較します。

---

### **Observableパターン**
Angularで`HttpClient`を使う場合、`HttpClient`メソッドは`Observable`を返します。  
```typescript
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class DataService {
  constructor(private http: HttpClient) {}

  // Observableを返す
  fetchData(): Observable<any> {
    return this.http.get('https://jsonplaceholder.typicode.com/posts');
  }
}

// 使用例
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-my-component',
  template: '<div *ngFor="let post of posts">{{ post.title }}</div>',
})
export class MyComponent implements OnInit {
  posts: any[] = [];

  constructor(private dataService: DataService) {}

  ngOnInit(): void {
    this.dataService.fetchData().subscribe((data) => {
      this.posts = data;
    });
  }
}
```

---

### **async/awaitパターン**
`Observable`を`Promise`に変換することで、`async/await`スタイルで同じ処理を記述できます。
```typescript
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class DataService {
  constructor(private http: HttpClient) {}

  // Promiseを返す
  async fetchData(): Promise<any> {
    return this.http.get('https://jsonplaceholder.typicode.com/posts').toPromise();
  }
}

// 使用例
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';

@Component({
  selector: 'app-my-component',
  template: '<div *ngFor="let post of posts">{{ post.title }}</div>',
})
export class MyComponent implements OnInit {
  posts: any[] = [];

  constructor(private dataService: DataService) {}

  async ngOnInit(): Promise<void> {
    this.posts = await this.dataService.fetchData();
  }
}
```

---

## **4. どちらを使うべきか？場面ごとの選択**

| 特徴                 | Observable                                       | async/await                                     |
|----------------------|------------------------------------------------|-----------------------------------------------|
| **複数の値を扱う**   | 複数の値（ストリーム）を処理可能                  | 単一の値の処理に最適                              |
| **リアルタイム処理** | WebSocketやイベントリスナーに最適                  | 不向き                                          |
| **シンプルな処理**   | サブスクリプションが必要なため、やや複雑            | 簡潔で読みやすい                                |
| **Angular推奨**      | `HttpClient`はデフォルトでObservableを返す          | ObservableをPromiseに変換すれば利用可能          |

### **Observableが適している場面**
- **ストリームデータ**: WebSocketやユーザーイベントなどの連続的なデータ。
- **リアクティブプログラミング**: データの流れや変化を監視する必要がある場合。

### **async/awaitが適している場面**
- **単発の非同期操作**: シンプルなAPI呼び出しやデータ取得。
- **可読性が重要**: 簡単な非同期処理を記述する際に最適。

---

## **おわりに**
Observableは柔軟で強力ですが、特定の場面ではasync/awaitの方がシンプルに記述できます。どちらを使うべきかは、プロジェクトの要件や非同期処理の特性に応じて選択することが重要です。この記事を参考に、あなたのプロジェクトで適切な方法を選んでみてください！

---

### **`番外編`**
`Observable` を `async/await` として扱うために使用する主要なメソッドは、`firstValueFrom` と `lastValueFrom` です。これらを紹介します。

### 1. **`firstValueFrom`**
`firstValueFrom` は、`Observable` の最初の値を `Promise` として取得するためのメソッドです。`Observable` が発行するデータの中で最初に出た値を取得し、`Promise` を解決します。

#### 使用例：
```typescript
import { Observable, firstValueFrom } from 'rxjs';

async function getFirstValue() {
  const observable = new Observable<number>((subscriber) => {
    subscriber.next(1);
    subscriber.next(2);
    subscriber.complete();
  });

  const value = await firstValueFrom(observable);
  console.log(`First value: ${value}`); // 出力: First value: 1
}

getFirstValue();
```

### 2. **`lastValueFrom`**
`lastValueFrom` は、`Observable` の最後の値を `Promise` として取得するためのメソッドです。`Observable` が完了するまで待機し、最後に発行された値を取得して `Promise` を解決します。

#### 使用例：
```typescript
import { Observable, lastValueFrom } from 'rxjs';

async function getLastValue() {
  const observable = new Observable<number>((subscriber) => {
    subscriber.next(1);
    subscriber.next(2);
    subscriber.next(3);
    subscriber.complete();
  });

  const value = await lastValueFrom(observable);
  console.log(`Last value: ${value}`); // 出力: Last value: 3
}

getLastValue();
```

### まとめ
- **`firstValueFrom`**: `Observable` の最初の値を `Promise` として非同期処理で取得する。
- **`lastValueFrom`**: `Observable` の最後の値を `Promise` として非同期処理で取得する。

どちらも、`Observable` を `async/await` で扱いたい場合に非常に便利なメソッドです。これにより、RxJS のストリームをシンプルな非同期処理として扱うことができます。