在 Angular 中使用 ngZone 来触发脏检查,达到页面和数据同步的目的。React 中也有类似重新执行 render 函数或者 functional component 来重新渲染页面的逻辑。
我们知道,ngZone 会触发很多不必要的检查,导致性能的丧失,React 也有类似重复渲染的问题。在 Angular 中我们会建议结合使用 Observable 和 async pipe 来通知 angular 数据变化了,请重复渲染。
我们先来看看第一个问题:
Angular 是如何通过 RxJS 提高性能的?
- Angular 是通过 class data 和 HTML template 来组成的。Template 通过 Directive 来实现数据和 HTML 的组成。可以理解成一个 Directive 树,从根到叶,一层一层调用,渲染。
- 当数据变化的时候,Angular 会重新执行 Directive,将渲染结果修改。并且会逐层传递。这就是所谓的脏检查。
1a | \ 2a 2b | \ 3a 3b2a的数据变了,2b的数据没变。2a就会被重新渲染。然后递归检查3a,3b。2b则不会发生变化,2b上所有的子节点也不会发生变化。
- 那么,脏检查时如何被触发的呢。Angular 认为,我们只要在任何数据有可能变化的时候,触发一次检查,就能有效的察觉到数据的变化。这个检查器,就是
ng-zone。这里不做赘述。 - 因为 ng-zone 本身检查的是可能触发数据的行为,比如,点击的按钮,setTimeout 执行,有异步的操作之类,这些行为其实是非常频繁的,这也会导致 angular 可能会频繁的触发脏检查。有没有可能只有 Template 中使用到的数据发生变化的时候才通知 Angular 进行脏检查呢。当然,就是保证 Template 中使用的都是
observable。这样,只有数据 emit 一个新的 value 的时候我们才会触发脏检查。从而提高了性能。
我们看看 React 中是如何触发界面渲染的?
- React 中没有 Template,取而代之的是 jsx,本质上是通过 js function 来表示一个 html 节点,这样就可以直接在 js 中写 html 渲染的逻辑。从而达到不使用 directive 的目的。本质上 template + directive 和 jsx 应该是等价的。
- React 中没有脏检查,只要数据变了,就会重新执行 render 函数或者 functional component.
- React 中没有 ng-zone, 而是要求数据必须通过 setState (class component) hooks (functional component)来修改,从而触发 component 的重新渲染。(这里等价于 angular 中使用 async pipe 的observable 来修改数据)。
对比一下 Angular 和 React 的渲染逻辑:
- Template + Directive == JSX
- observable + async pipe == setState or hooks
这样,我们可以看出,在不使用 ng-zone 的情况下,Angular 根 React 的渲染逻辑是类似的。但是别忘了,Angular 是有脏检查的。假设两个 component 有相同的数据结构:
1a
| \
2a 2b
| \
3a 3b
- 假设 2a 中的 3a 变化了。对于 angular 来说,1a 会被检查到变化了,触发脏检查,2a 重新渲染,2b 不变。 3a 触发检查,重新渲染,3b 不变。这里我们发现,只有 3a 的逻辑被重新执行了。
- 但是,对于 React 而言,因为不存在脏检查,1a, 2a, 3a 的 都会被执行一次。1a, 2a, 3a 的逻辑都会被重复运行一遍。