【问题标题】:How to test rendering speed in Angular如何在 Angular 中测试渲染速度
【发布时间】:2014-10-08 08:18:11
【问题描述】:

我们正在构建一个 Angular 应用程序,并试图弄清楚如何获得一些关于渲染各种页面所需时间的基准。我读过关于 performance.timing here 的文章,但这似乎只对非单页应用程序有用,因为当我导航到我们应用程序中的新视图时,计时数字不会改变。

理想情况下,我们可以插入一些代码来获取各种视图的渲染时间,并将其发布到我们的 Big Query 服务中。

关于如何在 Angular 应用中获取视图的时间信息有什么想法吗?

编辑:

更具体地说,您转到加载大型 ng-repeat 列表的路由(这对于性能而言不是最佳的),并且窗口在实际呈现列表中的项目之前有很长的延迟。我们想看看从大空白视图到呈现列表中的项目需要多长时间。

【问题讨论】:

  • 您到底想测量什么?有一些内置事件,例如$routeChangeStart$routeChangeSuccess。也许您可以订阅它们并使用User Timing API 记录时间。
  • 我得看看这些事件到底捕捉到了什么。我在上面添加了更多细节的编辑。
  • @runTarm 通过您的参考,我找到了$viewContentLoaded,这可能就是我要找的!
  • 仍未解决。 $viewContentLoaded 在我们转到路由时立即触发,而不是在实际呈现内容时触发。

标签: javascript angularjs performance performance-testing


【解决方案1】:

TypeScript / Angular (2+) 答案:

要对 Angular 渲染组件树所花费的时间进行基准测试,请在更改检测之前和之后进行测量。这将计算 Angular 创建所有子组件并评估 ngIfs / ngFors 等所需的时间。

有时当变更检测运行时,什么都不会发生变化,而且时间间隔会很小。只需寻找最长的时间间隔,这可能就是所有工作发生的地方。此外,最好为此使用 OnPush 更改检测策略。见http://blog.angular-university.io/onpush-change-detection-how-it-works/

@Component({...}) class 上方声明此 Timer 实用程序:

class Timer {
  readonly start = performance.now();

  constructor(private readonly name: string) {}

  stop() {
    const time = performance.now() - this.start;
    console.log('Timer:', this.name, 'finished in', Math.round(time), 'ms');
  }
}

在你的组件类中添加这个

private t: Timer;

// When change detection begins
ngDoCheck() {
  this.t = new Timer('component 1 render');
}

// When change detection has finished:
// child components created, all *ngIfs evaluated
ngAfterViewChecked() {
  this.t.stop();  // Prints the time elapsed to the JS console.
}

请注意,角度渲染与屏幕上的浏览器渲染(绘画)是分开的。这也需要时间。当您在 Chrome 时间轴工具(javascript 开发人员控制台 -> 性能 -> 记录)中看到带有大量“checkAndUpdateView”和“callViewAction”调用的 javascript(黄色)时,即发生 Angular 渲染。当您在 Chrome 时间轴工具中看到紫色标记为“正在渲染”时,这就是实际的浏览器渲染。

【讨论】:

    【解决方案2】:

    在做了一些实验后,我找到了一种方法来估算渲染视图所需的时间。

    场景:

    1. 路由到 Angular 应用中的页面
    2. 进行 AJAX 调用以获取冗长的项目列表
    3. 获取项目列表,传入ng-repeat ul
    4. 查看渲染列表

    在 Angular 应用程序中,ng-repeat 是一个臭名昭著的性能杀手,但它非常方便。 Here's a discussion on the performancehere.

    假设我们想要获得从 #3 到 #4 所需时间的近似值,因为测试 AJAX 调用性能非常简单。

    这里有一些上下文:

    <ul>
      <li ng-repeat="item in items">
        {{item.name}}
        <!-- More content here -->
      </li>
    </ul>
    

    在 Angular 控制器内部:

    // Get items to populate ng-repeater
    MyApiService.getItems(query)
      .then( function (data) {
        $scope.items = data;
        // When callback finishes, Angular will process items
        // and prepare to load into DOM
      }, function (reason) {
        console.log(reason);
      });
    

    @runTarm、$routeChangeStart$routeChangeSuccess$viewContentLoaded 提到的事件会在路由加载后立即触发,但在 DOM 渲染项目之前触发,因此它们不能解决问题。但是,通过实验,我发现一旦 AJAX 回调完成并设置 $scope.items,Angular 就会开始处理 items 并准备将 ng-repeat ul 插入 DOM 的阻塞操作。因此,如果您在 AJAX 调用完成后获取时间,并在回调中指定的 setTimeout 中再次获取时间,则 setTimeout 回调将排队等待,直到 Angular 完成转发器进程并为您获取在 DOM 渲染之前的一瞬间,为您提供最接近的渲染时间近似值。这不会是实际的渲染时间,但对我们来说缓慢的部分不是 DOM 完成它的工作,而是 Angular,这是我们想要衡量的。

    这是修改后的示例:

    // Get items to populate ng-repeater
    MyApiService.getItems(query)
      .then( function (data) {
        var start = new Date();
        $scope.items = data;
        // When callback finishes, Angular will process items
        // and prepare to load into DOM
        setTimeout( function () {
          // Logs when Angular is done processing repeater
          console.log('Process time: ' + (new Date() - start));
        }); // Leave timeout empty to fire on next tick
      }, function (reason) {
        console.log(reason);
      });
    

    【讨论】:

    【解决方案3】:

    试试开源的Chrome插件Angular-performance,可以在Angular应用中监控digest time:https://github.com/Linkurious/angular-performance

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-06
      • 1970-01-01
      • 2012-02-07
      • 1970-01-01
      • 2021-11-07
      • 2016-04-18
      • 1970-01-01
      • 2011-08-12
      相关资源
      最近更新 更多