尝试测量AngularJS应用程序的性能 – 使用angular-benchpress

在 AngularJS 参考文档的第二部分,我想要介绍 angular-benchpress。

    https://github.com/angular/benchpress

angular-benchpress是Angular团队开发的性能测量工具。
它不仅适用于AngularJS,还可以用于测量Web应用程序的客户端性能。
据说甚至在AngularJS和AngularDart的核心中也使用了这个工具进行性能测试。

安装和运行

如果已经安装了Node.js和npm,则可以使用以下命令进行安装。

$ npm install -g angular-benchpress

然而,需要注意的是,angular-benchpress的0.1.0和0.1.2版本存在一些小错误,导致发布时无法正常工作。
(对于v0.1.2版本,只需在cli.js的第88行benchmarksPath前添加一个加号即可修复。在github的master分支中已修复)

那么,我们试试运行AngularJS的性能测试吧。

$ git clone https://github.com/angular/angular.js.git
$ cd angular.js
$ grunt build
$ benchpress build
$ benchpress run

在AngularJS中,目前提供了两个性能测试选项。

    • http://localhost:3339/benchpress-build/event-delegation-bp/

 

    http://localhost:3339/benchpress-build/largetable-bp/

画面内容的描述 de

现在打开浏览器,然后尝试访问下面的URL。

    http://localhost:3339/benchpress-build/event-delegation-bp/

然后,会打开如下的画面。

benchpress1.png

这个界面被分成三个大的部分,上部是用于操作的面板,中间部分显示性能测试结果,下部以嵌入HTML的形式显示被测试对象。

选项
选项

画面的上方有三个选项卡,但通常只使用”控制”选项卡。

    • Controls: パフォーマンス計測の操作画面が表示されるタブ

Loop

Pauseを押すまで計測を繰り返す

Onece

1回だけ計測を実施

Loop 25x

25回計測を実施

Profile

ブラウザのプロファイラ機能を利用して処理時間を計測

Scripts: 計測に利用するスクリプトを、URLのパラメータで切り替えられることを解説しているタブ

例えば、AngularJS 1.2と1.3でどれくらいの性能差があるのか比較するときなどに利用すると便利です。

Tips: パフォーマンス計測をするときの注意点が書いてあるタブ

プラグインなどの影響を避けるために、計測の際にはシークレットウインドウを開いてからテストを実行しましょう
テストの実行中はマウスやキーボードに触らないようにしましょう

测量结果

那么,请打开控制选项卡,选择单选按钮的ngClick,并点击“重复25次”按钮试一试。
然后,结果将会在“结果”中输出如下所示。

benchpress2.png

在这个测试中,我们在使用1000个ngClick指令时测量了$scope.$apply的执行时间。
测量结果将显示以下4个项目。
除了性能测量外,还可以检查是否存在内存泄漏的情况。

    • test time (ms): 計測対象の処理を実行するのにかかった時間

mean: 平均値
stddev: 標準偏差
min: 最小値
max: 最大値

gc time (ms): ガベージコレクションの実行(window.gc)にかかった時間

mean: 平均値
combined: test timeとgc timeの合計

garbage (KB): ガベージコレクションにより解放されたメモリサイズ

mean: 平均値

retained memory (KB): ガベージコレクションで解放し忘れたメモリサイズ

mean: 平均値

AngularJS 1.2和1.3的性能比较

当尝试在AngularJS 1.2.23和1.3.0-rc.0上进行性能测试时,在Chrome 37环境下得到了以下结果。

event-delegation-bp_apply.png
largetable-bp_apply.png
largetable-bp_create.png
largetable-bp_destroy.png

听说AngularJS 1.3进行了大规模的性能改进!

我们来测试一下自定义过滤器指令的性能。

我們可以創建一個將Markdown格式的字符串轉換為HTML的過濾器和指令,並進行性能比較。
請預先從以下頁面下載marked.js。

    https://github.com/chjj/marked

首先按照以下方式实现Markdown过滤器和指令。省略说明。

angular.module('app', [])
  .filter('mdFilter', ['$sce', function ($sce) {
    return function (input) {
      if (angular.isDefined(input)) {
        return $sce.trustAsHtml(marked(input));
      } else {
        return "";
      }
    };
  }])
  .directive('mdDirective', function () {
    return {
      restrict: 'E',
      require: 'ngModel',
      link: function (scope, element, attrs, ctrl) {
        ctrl.$render = function () {
          if (angular.isDefined(ctrl.$viewValue)) {
            element.html(marked(ctrl.$viewValue));
          }
        }
      }
    };
  });

接下来我们准备一个用于性能测量的控制器。

angular.module('app')
  .controller('PerfController', ['$scope', '$rootScope', function ($scope, $rootScope) {
    $scope.testData = '# test\n' +
      '## hoge\n' +
      ' * list1\n' +
      ' * list2\n' +
      ' * list3\n' +
      ' * list3\n' +
      '## fuga';

    $scope.rows = [];
    for (var i = 0; i < 1000; i++) {
      $scope.rows.push(i);
    }

    benchmarkSteps.push({
      name: '$apply',
      fn: function () {
        $rootScope.$apply();
      }
    });
  }]);

$scope.testData是一个用于测试的Markdown格式字符串。
$scope.rows是用于显示1000次过滤器和指令的虚拟数据。

benchmarkSteps是angular-benchpress提供的全局变量。将希望测量性能的操作添加到这个数组中。
在这里指定测量$rootScope.$apply的时间。

然后,准备使用Markdown过滤器和指令创建HTML。

<div ng-app="app">
  <div ng-controller="PerfController">
    <label><input type="radio" ng-model="benchType" value="filter">filter</label>
    <label><input type="radio" ng-model="benchType" value="directive">directive</label>
    <div ng-repeat="row in rows">
      <ng-switch on="benchType">
        <div ng-switch-when="filter">
          <div ng-bind-html="testData | mdFilter"></div>
        </div>
        <div ng-switch-when="directive">
          <md-directive ng-model="testData"></md-directive>
        </div>
      </ng-switch>
    </div>
  </div>
</div>

这个HTML会被嵌入到benchpress模板中,所以不需要写head、body或script标签。
我们会使用单选按钮来切换过滤器和指令的显示。
同时,我们会使用ng-repeat来重复显示1000次过滤器和指令。

最后,需要准备配置文件。

module.exports = function (config) {
  config.set({
    scripts: [
      {
        id: 'angular',
        src: 'angular.js'
      },
      {
        id: 'marked',
        src: 'marked.js'
      },
      {
        src: 'app.js'
      },
      {
        src: 'perf.js'
      }
    ]
  });
};

请指定JavaScript文件来运行筛选器和指令。如果指定了ID,您可以在测试运行时通过URL切换文件。

将上述的5个文件和angular.js配置到名为benchmarks/markdown的目录中。(benchmarks名称固定,markdown可以任意命名)

然后,执行以下命令。

$ benchpress build

如果没有出现错误并且生成了名为benchpress-build的目录,则表示成功。
执行以下命令以启动基准测试。

$ benchpress run

让我们在浏览器中尝试访问下一页。

    http://localhost:3339/benchpress-build/markdown/

让我们切换过滤器和指令,并尝试在每个都执行25次循环。
在我的环境中,使用过滤器需要20毫秒,而使用指令只需要5毫秒。
通过这个例子我们可以看出,在这种情况下,指令似乎比过滤器更好。

总结

经常听说AngularJS相对于其他框架而言渲染较慢。然而,AngularJS 1.3进行了大量改进,而且应用程序对性能的需求各不相同。因此,为了了解我们预期的应用程序能达到什么样的性能水平,我们可以尝试使用angular-benchpress进行测试。