javascript - Angular 性能: change detection detached if component is out of viewport

标签 javascript angular intersection-observer

我想从当前视口(viewport)中分离所有组件的更改检测

see demo online

import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef, ElementRef, ViewChild, OnInit, OnDestroy, AfterViewInit } from '@angular/core';

@Component({
  selector: 'hello',
  template: `<div #counter>[{{index}}] {{count}}</div>`,
  styles: [`div { border: 1px solid red; padding: 5px 5px 5px 5px; }`],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HelloComponent implements OnInit, AfterViewInit {

  @ViewChild('counter', { static: false }) counter: ElementRef;
  @Input() index: number;

  public count = 0;
  public visible = true;

  constructor(private cdr: ChangeDetectorRef){}

  ngOnInit() {
    setInterval(() => {
      this.count++;
      this.cdr.markForCheck();
    }, 1000);
  }

  ngAfterViewInit() {
      const hideWhenBoxInView = new IntersectionObserver((entries) => {
        if (entries[0].intersectionRatio <= 0) { // If not in view
          this.cdr.detach();
          this.visible = false;
        } else {
          this.visible = true;
          this.cdr.reattach();
          this.cdr.markForCheck();
        }
        // console.log(this.index, this.visible);
      });
      hideWhenBoxInView.observe(this.counter.nativeElement);
  }
}

它可以工作,但是有超过 1000 个组件时,性能非常糟糕。

我的附加/分离更改检测正确吗?

最佳答案

您正在为每个组件调用 setInterval(),包括那些不在 View 中的组件。更改检测未运行,但您仍然每秒调用 setInterval() 中的函数 1000 次,这解释了延迟。

顺便说一句,渲染包含 1000 个项目的滚动列表也会影响性能。尽管在视口(viewport)之外,但浏览器将渲染所有内容,并且在滚动列表时需要计算各种绘制。您应该延迟渲染这么长的列表,请参阅 Virtual Scrolling in Angular 7

您还在 View 之外的组件上调用 .markForCheck(),请在调用之前检查组件是否可见。

参见StackBlitz

ngOnInit() {
  this.subscriptions.add(
    interval(1000).subscribe(() => {
      this.count++;
      if (this.visible) {
        this.cdr.markForCheck();
      }
    })
  );
}

ngOnDestroy() {
  this.subscriptions.unsubscribe();
}

ngAfterViewInit() {
  const hideWhenBoxInView = new IntersectionObserver(entries => {
    if (entries[0].intersectionRatio <= 0) {
      // If not in view
      this.cdr.detach();
      this.visible = false;
    } else {
      this.visible = true;
      this.cdr.reattach();
      this.cdr.markForCheck();
    }
  });
  hideWhenBoxInView.observe(this.counter.nativeElement);
}

CPU Profile

关于javascript - Angular 性能: change detection detached if component is out of viewport,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59248167/

相关文章:

Angular,如何阻止与父组件的键盘交互

javascript - 如何使 IntersectionObserver 与变换平移动画一起使用?

javascript - Vue设置IntersectionObserver

javascript - 如何使用 jQuery 在一个 div 中查找某个字符串,然后将特定样式应用于另一个 div(如果存在)?

javascript - 日语字符的字符串比较

javascript - Priority-Web-SDK:过滤表单

javascript - 使用 IntersectionObserver 实现粘性 header

javascript - 错误: done() called multiple times when trying to implement multiple interactions in pact javascript

angular - 类型错误 : Cannot read property 'canDeactivate' of null

angular - 如何检查来自父路由器或父路由器的事件子路由器?