3
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?

More than 5 years have passed since last update.

Business Bank Group DevelopersAdvent Calendar 2018

Day 10

「Pure JavaScript vs Lodash」の結果をAngular app内でグラフ表示してみた

Last updated at Posted at 2018-12-10

この記事は、Business Bank Group Developers Advent Calendar 10日目の記事です。


こんにちは、BBGの清水です。
おとといのアドベントカレンダーで、Pure JavaScript vs Lodashという内容を書きました。
せっかく計測したので、それをグラフで表示して可視化してみたいなー
Angular Materialさわってみたいなー
という思いを込めたアプリをAngularCLIで作ってみました。

開発環境

  • Angular: 6.1.10
  • Angular CLI: 6.1.5
  • Angular Material: 7.1.1

実装

今回は、MatTableModuleを使用してタブ表示をしています。
また、グラフはNGX-CHARTSを使用しました。
開発環境に@angular/material, @swimlane/ngx-chartsを入れたら、必要なmoduleをapp.moduleにimportするだけで簡単にタブ・グラフ表示ができました。

app.module.ts
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatTableModule, MatTabsModule, } from '@angular/material';

使う側はこんな感じです。

app.component.html
<div style="text-align:center">
  <h1>Pure JavaScript vs Lodash</h1>
</div>
<div class="body">
  <!-- Patternごとに結果をタブ切り替えで表示させた -->
  <mat-tab-group mat-align-tabs="start">
    <mat-tab label="Pattern1">
      <app-pattern1></app-pattern1>
    </mat-tab>
    <mat-tab label="Pattern2">
      <app-pattern2></app-pattern2>
    </mat-tab>
    <mat-tab label="Pattern3">
      <app-pattern3></app-pattern3>
    </mat-tab>
  </mat-tab-group>
</div>
pattern1.component.html
<div class="wrapper">
  <div class="content">
    <button mat-stroked-button (click)="onClick()">
      StartMeasuring!
    </button>
    <ng-container *ngFor="let item of displayData">
      <div class="average">
        <span class="{{item.class}}">{{item.label}}</span>
        <span class="value">{{item.average}} (ms)</span>
      </div>
    </ng-container>
  </div>
  <!-- グラフ表示 -->
  <ngx-charts-line-chart
    [view]="view"
    [results]="inputData"
    [xAxis]="true"
    [yAxis]="true"
    [legend]="true"
    [showXAxisLabel]="true"
    [showYAxisLabel]="true"
    xAxisLabel="times"
    yAxisLabel="(ms)">
  </ngx-charts-line-chart>
</div>
pattern1.component.ts
import { Component } from '@angular/core';
import * as _ from 'lodash';

interface SeriesInterface {
  value: number;
  name: number;
}
interface InitialDataInterface {
  a: number;
}

@Component({
  selector: 'app-pattern1',
  templateUrl: './pattern1.component.html',
  styleUrls: ['./pattern1.component.css']
})

export class Pattern1Component {
  view = [750, 450];
  roopCount = 50;
  inputData: { name: 'PureJS' | 'Lodash', series: SeriesInterface[] }[] = [];
  displayData: { label: string, average: number, class: string }[] = [];

  constructor() {}

  onClick() {
    const data1: InitialDataInterface[] = [];
    const data2: InitialDataInterface[] = [];
    Array.from({ length: 10000 }, () => {
      const num = Math.random();
      data1.push({ a: num });
      data2.push({ a: num });
    });

    const result1: SeriesInterface[] = [];
    const result2: SeriesInterface[] = [];
    Array.from({ length: this.roopCount }, ({}, index) => {
      result1.push({ value: this.pureJS(data1), name: index });
      result2.push({ value: this.lodash(data2), name: index });
    });

    this.inputData = [ { name: 'PureJS', series: result1 }, { name: 'Lodash', series: result2 } ];
    this.inputData.forEach((item, i) => {
      this.displayData.push({
        label: `${item.name}Average: `,
        average: this.calcAverage(item.series),
        class: `label${i + 1}`,
      });
    });
  }

  calcAverage(result: SeriesInterface[]): number {
    return _.sum(result.map(o => o.value)) / this.roopCount;
  }

  pureJS(data: InitialDataInterface[]): number {
    const startMs = performance.now();
    let sum = 0;
    data.map(o => o.a)
      .filter(a => a % 2)
      .forEach(n => sum += n);
    return performance.now() - startMs;
  }

  lodash(data: InitialDataInterface[]): number {
    const startMs = performance.now();
    _.chain(data).map('a')
      .filter(a => a % 2).sum().value();
    return performance.now() - startMs;
  }
}

Angular Material はcomponentごとにstackblitzが用意されていて、ちょっとした動作確認やイメージを掴むのにとても便利でした。
MatTableModuleのタブ切り替えのUXがかっこよくて個人的にとても好きです。

グラフは、NGX-CHARTSのLine Chartを使用しています。
グラフのマウスオーバー時の挙動はこんな感じです。
スクリーンショット 2018-12-09 23.50.03.png

可視化の結果

(グラフをみやすくするために、平均値はそれぞれ50, 50, 10回の結果を表示しています。)

Pattern 1

スクリーンショット 2018-12-09 23.35.31.png 平均値はPureJSが早いですが全体的に結果がまばらです。 あと、Lodashの最初の1回目に時間かかっているのが気になります。。(データの作り方が悪いのかな。。) #### Pattern 2 スクリーンショット 2018-12-09 23.35.37.png PureJSがLodashを上回ることは一度もなかったです。 #### Pattern 3 スクリーンショット 2018-12-09 23.35.44.png 前回の記事のコメントで[@pocke](https://qiita.com/pocke)さんが、PureJSのより良い実装を教えてくれたのでそちらのケースをPureJSAverage2として追加しています(ありがとうございます!) その結果、処理の仕方によって計測結果が大きく変わることが分りました。(PureJSAverage1, PureJSAverage2)

さいごに

今回は、Angular CLIとNGX-CHARTSを使って簡単にデータを可視化することができました!
やはりグラフ化されるとデータが見やすくていいですね。以上です!

明日は、@keitatakahashiさんです。
お願いします!

3
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
3
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?