17
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Angularにおけるパイプ(PurePipe, ImpurePipe)とメソッドの違い

Last updated at Posted at 2017-08-01

AngularでPipeを使うメリットとしては、「単純で、あらゆるコンポーネントでよく使うようなデータ整形処理は共通化して、Template(html)で記述できるようにする」というものです。

たとえば、%表記というのは内部的には 1.0 === 100% ですが、その変換は単純かつよく使うものです。

num1 = 2.5; 

のときに

{{num1 | percent}} 

と、PercentPipeを使って書くと、ビューの出力は

250%

になります。

Built-in Pipe として標準で用意されてるパイプには、下記のようによく使う単純なものが多いです。。

  • DatePipe : 日付変換(yyyy/mm/dd形式等)
  • DecimalPipe : 小数点切り捨て&ゼロうめ(3.141592 -> 003.14)
  • JsonPipe : object->json化(JSON.stringifyと同じ)
  • PercentPipe : パーセント表記(0.4 -> 40%)
  • SlicePipe : 先頭n文字から、末尾m文字までを切り出す。
  • CurrencyPipe : 通貨書式変換(USD->$,等)
  • UpperCasePipe, LowerCasePipe, TitleCasePipe : 大文字小文字変換。(日本語だと必要性があまり理解できないが、英語圏では使用頻度高い)

PipeにするかMethodにするか

さて、似たようなことをするときに、カスタムPipeを作るか、Componentのメソッドにするか迷うときがあります。

また、PipeにはImpure(不純)パイプとPure(純粋)パイプがあり、Pureパイプが標準となっています。

この違いを簡単にテストしてみましょう。
https://plnkr.co/edit/cOhEpn9gAUBoKbFvDRtA?p=preview

  • purePipe -> method -> impurePipe の順に無駄な実行が少ない。
  • 変更検知(ChangeDetection)の関係で、methodは無駄に複数回呼ばれる。pipeは変更検知後にしか実行されないのでパフォーマンスが良い。
  • impurePipeはホント無駄に呼ばれる。
  • methodのほうがpurePipeより実行される回数が多くなっちゃう
    • ただし描画処理前に実行されるから、描画に与える影響は超軽微
    • 重い原因は大抵はDOM変更が重い。jsは軽い。
    • <div>{{ date.toString() }}</div> は、 date.toString() の実行結果が変わらない限りDOM変更されない。
    • ただ、purePipeだと date値で比較し変化があったときのみpipeメソッド実行するのに比べ、 method/impurePipeは date.toString() の実行結果で比較する感じ。

結論

■ pipeは共通処理・軽い処理・純粋関数のみにする

カスタムPipeにするかMethodにするか悩むときは、Pipeの元々の定義に従い

  • (ビューでやるような)単純な変換か?
  • 多くのコンポーネントで使用頻度が高くそのための共通化すべきか?

あたりを判断基準にするべきで、「描画速度向上の為にPipeにしよう!」ということは避けるべきでしょう。

■ 配列をソートやフィルタするpipeは作らない

コンポーネントのプロパティに sortedArrayfilteredArray を作るほうがパフォーマンスが良い。
変更検知のタイミングとか実行処理が重いからとか色々ある。
詳しくは 公式ドキュメントにわざわざ項目作られてる ので参照してください(英語)。

■ メソッドは、ごく軽量なもの以外はtemplate内では使用しない

<h1>{{ getUserName(user.id) }} の BMI値 </h1>
<div>{{ user.calcBMI() }}</div>

こういうものは避ける。 getUserName() メソッドが裏でSQLやHTTPリクエストを実行していた場合、変更検知(ChangeDetection) が実行されるたびにSQL/HTTPを発行してしまう。

user.calcBMI() が内部的に user.weight / (user.height * user.height) を呼び出してるだけの場合、テンプレート中で

<div>{{ user.weight / (user.height * user.height) }}</div>

とするのと処理の負荷は(ほぼ)変わらない。 (関数呼び出しのオーバーヘッドとか、スマホで3万回の試行で30ms程度の差)

ただし、可能ならコンポーネント初期化時に、下記のように初期化したほうが良い。
理由としては、テンプレートで複雑に処理を記述すると、見通しが圧倒的に悪くなるため。

user.bmi = user.weight / (user.height * user.height);

// templateで
<div>{{ user.bmi }}</div>

メソッド実行や計算は、テンプレート中からは除外したほうが無難。 動作するし、テスト中には便利なんですけどね。

ChangeDetectionが走るタイミングで、これらのメソッド実行や計算は、何度も何度も起きることになる。(値が変わってなくても!)

17
9
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
17
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?