Observableとasync/awaitの違いを理解する
はじめに
AngularやTypeScriptでは、非同期処理を扱う際に主に以下の2つのパターンが使われます:
- Observable(RxJS)
- async/await(Promiseベース)
両者は非同期処理を扱うための方法ですが、それぞれに特徴や適した場面があります。この記事では、両者の基本的な使い方と、それぞれを使った非同期処理の実装例を解説します。
目次
- Observableの基本
- async/awaitの基本
- Observableとasync/awaitの実践例
- どちらを使うべきか?場面ごとの選択
1. Observableの基本
ObservableはRxJSライブラリによって提供される非同期処理のツールです。特徴として、ストリーム(複数の値を時間に沿って配信)を扱える点があります。
基本的な使い方
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を使って非同期処理を直感的に記述できる方法です。一度に単一の値を扱います。
基本的な使い方
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
を返します。
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
スタイルで同じ処理を記述できます。
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
を解決します。
使用例:
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
を解決します。
使用例:
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 のストリームをシンプルな非同期処理として扱うことができます。