immutable 在三大框架中的使用情况
vue: proxy + 发布订阅 + diff + virtual dom
react: setState + render + diff + virtual dom
angular:zone (异步事件做一层代理包裹,触发脏值检测) + immutable data + onPush 模式优化 + Observable 处理非引用类型
二、vue 中没有 immutable
尤大神认为脏检查会增大性能开销,因此采用set,get的proxy模式手动促发变更(既模板变量必须存储在特定对象中)。vue 原理就是利用了js Mutable 的特性,在 getter setter 上做拦截,所以对于那些 js array 会造成突变的函数需要做包裹,以实现数据变更的监听。
三、react hooks 的 immutable
而 react 为了兼容浏览器等原因?在数据监听上是利用了 setState 这一 api 。 react 没有 immmutable 处理(单独使用 immutable 库,不考虑在内)。但在 16.8.0 后 hooks 的引入, 每个 state 在函数重新执行时都是重新计算的,都是一个新的引用,所以 hooks 中,每个 state 都是 immutable 的。immutable 的优点是,很少会写出坑(不会发生悄悄改了数据,不 rerender),但也带来了 re-render 的性能消耗,因为每个 state 都是 diff 的,react 对应的解决方案是什么呢?useCallback, useMemory 声明依赖项等,进行是否重计算。
const memoizedValue=useMemo(()=>computeExpensiveValue(a,b),[a,b]);
四、Angular>=2.x 的 immutable
一些异步时机(事件、http、setTimeout)结束后会进行响应的dirty 检测,angular/zone.js 暴力代理所有可能引发变更的操作。
用 immutable 和 onPush ,使得 dirty 检测变得简单,性能高。onPush 模式下,一旦某个节点没有变更,则不检查其子节点。immutable 使得只需要判断是否有引用变更,就知道是否有变更。
但有些数据引用是不会变的,这样怎么视图的更新呢,这就用到了 Observable 事件流,对数据变更进行了订阅,同时 angular 又提供了一个 markForCheck 对该节点的链路进行变更检测标记。
五、思考
1、setState为什么批量更新模式不会同步更新组件状态?
react 的 render 执行需要一个通知去执行,如果每次都同步修改了,那 render 函数执行的条件将难以判断,如果每次都 render 会有性能问题,而且 shouldComponentUpdate和componentWillUpdate里,this.state还没有改变,如果是同步的,这两个函数也会有问题。
2、virtual dom VS Incremental DOM?
vue、react :浏览器渲染引擎与 virtual dom 。模板被编译到render函数
angular 8+:angular lvy 渲染引擎和 Incremental DOM, 组件自带更新指令。模板被编译到指令
3、diff 与 脏检查?
vue、react :diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。
angular :脏检查。props 变更 与被标记的脏路径。
4、redux、vuex 与rxjs
vue react: redux、vuex 进行状态管理
angular: rxjs 函数式响应式编程
5、vue 为什么不需要 shouldUpdatecomponent , React.memo ,PureComponent 这种性能优化的 api?
vue 因为本身发布订阅模式,就知道对应的对象变更。
6、vue 进行 diff 、 react 进行 diff 时机的不同、angular 进行脏值检测的时机不同。
vue 的更新是异步的批量的,数据变更是同步的。diff 的 时机是 event loop 的切换时机。
react 的更新是异步的批量的,数据变更是异步的。 diff 的时机是 : 是否批量更新模式,也就是是否处于 react 事务中
angular 是 zone 中对异步事件进行了包装,只要有异步的事件,就会进行一次脏值检测, dirty 检测同时更新 dom,非批量更新?。
六、相关阅读