Angular 性能优化

757 阅读3分钟

*ngFor 添加 trackBy

官方文档,查看“变更的传导机制”即有详细的表述:

即使数据没有变化,迭代器中的元素标识符也可能会发生变化。比如,如果迭代器处理的目标是通过 RPC 从服务器取来的, 而 RPC 又重新执行了一次。那么即使数据没有变化,第二次的响应体还是会生成一些具有不同标识符的对象。Angular 将会清除整个 DOM, 并重建它(就仿佛把所有老的元素都删除,并插入所有新元素)。这是很昂贵的操作,应该尽力避免。

那么如何来避免呢?

要想自定义默认的跟踪算法,NgForOf 支持 trackBy 选项。trackBy 接受一个带两个参数 index 和 item 的函数。 如果给出了 trackBy,Angular 就会使用该函数的返回值来跟踪变化。

使用纯管道(pure pipe), 减少重复运算

纯管道transform() 方法只有在其输入参数变化时才会被调用。管道默认都是纯管道。

非纯管道: 该管道具有内部状态(也就是说,其结果会依赖内部状态,而不仅仅依赖参数),就要把 pure 设置为 false。 这种情况下,该管道会在每个变更检测周期中都被调用一次 —— 即使其参数没有发生任何变化。

避免频繁触发变更检测

Angular中的变更检测机制是当component状态有变化的时候,angular都能检测到这些变化,并且能够将这些变化反应到页面上。虽然angular变更检测本身性能很好,在毫秒内可以做成百上千次变化检测。但是随着项目越来越大,很多不必要的变化检测还是会在一定程度上影响性能。

Angular 的默认变更检测机制

Angular的变更检测是事件驱动,来源有以下三大类:

  • 事件:页面 click、submit、mousedown……
  • XHR:从后端服务器拿到数据
  • Timers:setTimeout()、setInterval()。

如何监听事件不触发变更检测

Angular 外的监听: runOutsideAngular

runOutsideAngular() 使你的上下文不会触发Angular跟踪变化。 如果你想继续跟踪变化,使用**run()**方法即可让Angular重新跟踪变化。

onPush 策略

onPush策略,用以跳过某个component以及它下面所有子组件的变化检测。也就是当进行组件树的变更检测的时候,将使用了该策略的组件其所有的子组件会排除。

在使用了OnPush策略以后,组件内部将自己触发变更检测,触发方式有:

1)组件的@Input属性的引用发生变化; 2)组件内的DOM事件,包括它子组件的DOM事件,比如click、submit、mousedown; 3)组件内的Observable订阅事件,同时设置Async pipe; 4)组件内手动使用ChangeDetectorRef.detectChanges()、ChangeDetectorRef.markForCheck()、ApplicationRef.tick()方法。

diff 和 immutable

diff

IterableDiffer

interface IterableDiffer<V> {  diff(object: NgIterable): IterableChanges | null }

用来跟踪一个迭代内的更改的策略。NgForOf 使用它通过对 DOM 进行等效更改来响应此迭代内的更改。

KeyValueDiffer

跟踪对象随时间变化的差异。

interface KeyValueDiffer<K, V> {  diff(object: Map<K, V>): KeyValueChanges<K, V> | null }

immutable

Immutable data cannot be changed once created, leading to much simpler application development, no defensive copying, and enabling advanced memoization and change detection techniques with simple logic. Persistent data presents a mutative API which does not update the data in-place, but instead always yields new updated data.

angular 生命周期优化

angular生命周期.png

  • 请不要在生民周期钩子中实现复杂的业务逻辑,尤其是那四会反复执行的钩子(ngOnChange, ngDoCheck, ngAfterContentChecked, ngAfterViewChecked),否则会造成界面卡顿。

  • ngOnInit 在绘制之前,ngAfterViewInit 在绘制之后。日志发送、网络请求等写在constrouctor, ngOnInt 中,实质上是延误了绘制。

  • 无关绘制的逻辑,建议写在ngAfterViewInit 中。