0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【実務で迷わない】Promise vs Observable + Angular が Observable を採用する理由

Posted at

この記事の目的

  • Promise と Observable の違いを 業務レベルの具体例 で理解する
  • UI フレームワーク(特に Angular)で Observable が選ばれる理由を知る
  • 「いつ Promise を使い、いつ Observable を使うべきか」を判断できるようになる

想定読者

  • TypeScript / Angular の実務経験 1〜3 年目
  • RxJS を“なんとなく”使っているが、本質を掴みたい人
  • Angular の HttpClient が Promise を採用しない理由を知りたい人

1. Promise と Observable の違い(業務で発生する問題から理解する)

■ Promise が「バグの原因になる」典型パターン

ケース1:サジェスト検索(入力のたびに API 呼び出し)

Promise で実装すると…

  • 高速タイピングで 前の API をキャンセルできない
  • 古いレスポンスが後から返って UI が書き換わる
  • → 実務で最も多い UI バグ

Observable なら…

  • debounceTime:入力が落ち着くまで待つ
  • distinctUntilChanged:同じ内容は無視
  • switchMap:古いリクエストを自動キャンセル

ケース2:5秒ごとの API ポーリング(在庫確認・セッション延命)

Promise:

  • setInterval と then が混じり可読性が低い
  • 中断が難しい

Observable:

interval(5000).pipe(
  switchMap(() => this.http.get('/api/status'))
).subscribe(status => updateUI(status));

ケース3:画面遷移後に非同期処理が返り UI が壊れる

Promise:

  • キャンセル不可
  • 画面破棄後に値が返り UI が壊れる
  • メモリリークの原因にもなる

Observable:

  • unsubscribe により確実に停止

2. Angular の HttpClient が Observable の理由(深掘り)

★理由1:HTTP は「単発」ではなく「UI 状態の一部」だから

SPA では以下が日常的に起きる:

  • 入力値の変化
  • 再リクエスト
  • 画面遷移
  • リアルタイム更新

Promise は「単発前提」のため UI 変化に追従できない。
Observable は 継続する値の流れ(ストリーム) なので UI と相性が良い。

★理由2:HTTP キャンセルが必須(Promise では不可能)

UI では高速操作が当たり前。

  • ユーザーが検索ワードを連続入力
  • 画面移動中に API が返る
  • 古い結果が UI に反映される危険

Observable → unsubscribe() ができる
Promise → ❌ できない

★理由3:switchMap による「古いリクエストの自動キャンセル」

this.keyword$.pipe(
  debounceTime(300),
  distinctUntilChanged(),
  switchMap(keyword => this.http.get(`/api/search?q=${keyword}`))
).subscribe(console.log);

★理由4:非同期処理と UI 状態の合成を容易にするため

Promise:

  • then チェーン地獄
  • 複雑な合成が難しい

Observable:

  • combineLatest
  • map, switchMap, catchError

★理由5:メモリリーク防止(unsubscribe)が重要

Promise:

  • 停止できず処理が残る → メモリリークの温床

Observable:

  • 破棄時に unsubscribe → 安全

3. 結論:Angular が Observable を採用した理由まとめ

Angular が必要とする要件 Promise Observable
UI と同期した API 呼び出し
キャンセル
古いリクエストの破棄
ポーリング
複数ストリームの合成
メモリリーク防止

4. サンプルコード:サジェスト検索

@UntilDestroy()
@Component({
  selector: 'app-search',
  template: `<input (input)="onInput($event.target.value)" />`
})
export class SearchComponent {
  private keyword$ = new Subject<string>();

  results$ = this.keyword$.pipe(
    debounceTime(300),
    distinctUntilChanged(),
    switchMap(keyword =>
      this.http.get(`/api/search?q=${keyword}`)
    )
  );

  constructor(private http: HttpClient) {}

  onInput(value: string) {
    this.keyword$.next(value);
  }
}

5. 例え話:Promise vs Observable

Promise = 単発の宅配便

  • 送れば届く
  • キャンセル不可
  • 住所(UI)が変わっても持ってこられる(バグの原因)

Observable = 配送システム

  • 状態が変われば配送先も変わる
  • 配送停止(unsubscribe)が可能
  • イベント・入力・ポーリングなどの連続値に対応

6. まとめ

  • Promise は「単発処理」向け
  • Observable は「UI × 非同期」向け
  • Angular の HttpClient が Observable を採用する理由は
    UI の安全性・柔軟性・キャンセル制御 を満たすため
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?