非同期サービス

Angular と仲直りをしている

まえがき

昇進してからというもの、公私ともに Angular と戯れる時間がめっきり減ってしまった。

このたび、自分へのご褒美 (?) に Surface Pro LTE Advanced を入手し、真にポータブルな開発環境を手に入れたので、きちんと刃を研ぐ習慣を身に着けたい今日この頃。

そうこうしているうちに Angular 6.1 もリリースされたことなので、ここらで「分かっているようで実は分かっていなかったこと」の総復習をしようと思った。

ここまで前置き。

今回は、Angular の Service で非同期処理ってどう捌くんだっけ、という話。

いきなり結論

結論から言うと、Observable<T> を返すメソッドを書けばよい。 たったそれだけ。

たとえば、50ミリ秒おきにランダム値を40回生成し続ける非同期 Service はこんな感じになる。

import { Observable, interval } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class DummyService {
  getId(): Observable<number> {
    return interval(50)
      .pipe(
        take(40),
        map(() => Math.random())
      );
  }
}

すっかり忘れていたけど、RxJS は v6.0 以降、メソッドチェーンではなく .pipe()パイプ の引数に連ねる書き方に変わったのであった。

利用するコンポーネント側。

import { Component, OnInit } from '@angular/core';
import { DummyService } from '../dummy.service';

@Component({
  selector: 'app-home',
  template: `<div>{{id}}</div>`
})
export class HomeComponent implements OnInit {
  id: number;
  constructor(private dummyService: DummyService) { }

  ngOnInit() {
    this.dummyService.getId().subscribe(
      ret => this.id = ret,
      err => {
        this.id = undefined;
        console.log(`Error Occurred: ${err}`);
      },
      () => console.log('Completed!')
    );
  }
}

こう書くと、Service からストリームが届くたびに id プロパティが更新される。

また、Service の気が済んだら(すなわち終了したら)、コンソールに Completed! という断末魔を吐いたのちに購読を止める。

思えば、HttpClient を利用した非同期通信を見れば明らかだった。 なぜ気付かなかったのだろう。

今後の課題

ここまでは基礎中の基礎で、これをもう少し掘り下げて考えねばならない。

  • 非同期処理の最中に submit が行われないようにする
  • 非同期入力チェックの最中に、当該入力欄が書き換えられないようにする

あるいは

  • submit が行われた場合、処理中の非同期処理を待ち合わせる
  • 入力欄が書き換えられるたびに(実行中の非同期チェックをキャンセルした上で)再チェックを行う

といった配慮が必要だ。

ただ、こういうことを考えるのはあまり面白くないので、後に回すかもしれない。