前端框架是什么 框架是什么( 二 )


angular 则是基于脏百思特网检查,在每个可能改变数据的逻辑之后都对比下数据是否变了,变了的话就去更新 dom 。
react 则是不检查,不检查难道每次都渲染全部的 dom 么?也不是,不检查是因为不直接渲染到 dom,而是中间加了一层虚拟 dom,每次都渲染成这个虚拟 dom,然后 diff 下渲染出的虚拟 dom 是否变了,变了的话就去更新对应的 dom 。
这就是前端框架的数据驱动视图变化的三种思路 。
vue 是组件级别的数据 watch,当组件内部监听数据变化的地方特别多的时候,一次更新可能计算量特别大,计算量大了就可能会导致丢帧,也就是渲染的卡顿 。所以 vue 的优化方式就是把大组件拆成小组件,这样每个数据就不会有太多的 watcher 了 。
react 并不监听数据的变化,而是渲染出整个虚拟 dom,然后 diff 。基于这种方案的优化方式就是对于不需要重新生成 vdom 的组件,通过 shouldComponentUpdate 来跳过渲染 。
但是当应用的组件树特别大的时候,只是 shouldComponentUpdate 跳过部分组件渲染,依然可能计算量特别大 。计算量大了同样可能导致渲染的卡顿,怎么办呢?
树的遍历有深度优先和广度优先两种方式,组件树的渲染就是深度优先的,一般是通过递归来做,但是如果能通过链表记录下路径,就可以变成循环 。变成了循环,那么就可以按照时间片分段,让 vdom 的生成不再阻塞页面渲染,这就像操作系统对多个进程的分时调度一样 。
这个通过把组件树改成链表,把 vdom 的生成从递归改循环的功能就是 react fiber 。
fiber 节点相对于之前的组件节点来说,没有了 parent、children 这种属性,多了 child、sibling、return 属性 。
通过 fiber 链表树,优化了渲染的性能 。
可以看到 vue 的性能优化和 react 百思特网的性能优化是不一样的:
vue 是组件级别的数据监听的方案,问题可能出现在一个属性太多 watcher 的时候,所以优化思路就是大组件拆分成小组件,保证每个属性不要有太多 watcher 。
react 不监听、不检查数据变化,每次都渲染生成 vdom,然后进行 vdom 的对比,那么优化的思路就是 shouldComponentUpdate 来跳过部分组件的 render,而且 react 内部也做了组件树的链表化(fiber)来把递归改成可打断的渲染,按照时间片来逐渐生成整个 vdom 。
组件之间难免要有逻辑的复用,react 和 vue 有不同的方案:
vue 的组件是 option 对象的方式,那么逻辑复用方式很自然可以想到通过对象属性的 mixin,vue2 的组件内逻辑复用方案就是 mixin,但是 mixin 很难区分混入的属性、方法的来源,比较乱,代码维护性差 。但也没有更好的方案 。
react 刚开始也是支持 mixin 的,但后来废弃了 。
react 的组件是 class 和 function 两种形式,那么类似高阶函数的高阶组件(high order component)的方式就比较自然,也就是组件套组件,在父组件里面执行一部分逻辑,然后渲染子组件 。
除了多加一层组件的 HOC 方式以外,没有逻辑的部分可以直接把那部分 jsx 作为 props 传入另一个组件来复用,也就是 render props 。
HOC 和 render props 是 react 的 class 组件支持的两种逻辑复用方案 。
最开始的 function 组件是没有状态的,只是作为 class 组件渲染的辅助而存在 。
但是 HOC 的逻辑复用方式最终导致了组件嵌套太深,而且 class 内部生命周期比较多,逻辑都放在一起导致了组件比较大 。
怎么解决 class 组件嵌套深和组件大的问题呢?而且还不能引入破坏性的更新,不然下场可能会很惨 。
于是 react 团队就瞅准了 function 组件,能不能在 function 组件里面也支持 state,通过扩展一些 api 的方式来支持,也不是破坏性的更新 。

推荐阅读