本文的 React 多态性应该是 Redux 的多态性,整篇文章都在论述 Redux,但是 Redux 的场景不局限于 React
-
Redux immutable 的特性可能造成浏览器无法优化的性能问题 (参考上篇文章的浏览器 Shapes && Inline caches),看看普通 Redux 下的场景:
-
const todo = (state = {}, action) => { switch(action.type) { case "ADD_TODO": return { id: action.id, text: action.text, completed: false } case "TOGGLE_TODO": if (state.id !== action.id) { return state } return Object.assign({}, state, { complete: !state.completed }) default: return state } }
-
通过简化使用场景,可以拆分出两个新的 store
s1
s2
:-
cosnt si = todo({}, { type: "ADD_TODO", id: 1, text: "Finish blog post" }) const s2 = todo({}, { type: "TOGGLE_TODO, id: 1 })
-
-
看上去不会耦合到一个 redux 里面去,每次的 dispatch 都会根据 reducer 生成新的 store 树,并且是一个新的对象,虽然对于 js 引擎来说,代码做不了 Shapes 优化,也就是需要做优化的全局 store 在生成新的 store 时无法被浏览器优化,虽然容易被忽略,但是影响不小
-
// shapes为什么不能优化 let a = {x: 1, y: 2, z: 3} let b = {} b.x = 1 b.y = 2 b.x = 3 // 原因是没有一个共用的Shapes {x, y ,z } 或者是 {} 形似的shapes (V8引擎的Shape称为Map) // 使用 node --allow-natives-syntax 调用node原生函数 %HaveSameMap 判断两个对象是否共享一个shape %HaveSameMao(a, b) // false
-
结果为 false 表明 js 引擎无法为 a 和 b 两个对象做优化,因为其初始化方式不一样,Shapes 不一致
-
同样 Redux 常用的 Object.assign 也有这个问题,因为新的对象是{}作为初始状态,js 引擎会为新对象创建 Empty Shape,跟原对象的 shape 一定不一致,es6 的解构语法同样存在此问题,因为 babel 会将解构转译为
Object.assign()
-
对于这种无法优化的情况,建议所有对象赋值的时候使用
Object.assign({}, xxx)
保证 js 引擎使用公共的 Shapes 做优化let a = Object.assign({}, {x:1 , y: 2, z: 3}) let b = Object.assign({}, a) console.log("a and b have same map", %HaveSameMap(a, b)) // same Shape: true
-
-
- 作者对于 React-redux 的性能问题实际是引擎级别的 Shapes 的优化问题, 只有相同初始化方式的对象才会引用同一个 Shapes 做优化,而 immutable 全局 Store 往往是不能被优化的,因为其赋值往往采用的是
Object.assign()
或者解构的形式赋值,这样产生的新对象的 Shapes 跟原对象的 shapes 不同,导致无法对 Shapes 做复用。 - Immutable 对象之间虽然是不同的引用,但是 JS 引擎级别优化的目的是在不同对象引用的时候做公共 Shapes 查找并且优化,对象的结构如果是公共的 Shapes,那么只会将 Shapes 和数据分离,优化存储效率,数组的 Elements 也一样。
- 作者是推荐使用 immutable-js 操作 immutable 对象,而不是使用 Object.assign,因为封装库内部可能通过统一对象初始化的形式在 JS 引擎层面上进行优化的。
- 原文多态(polymorphic)其实是多个相同结构的对象,拆分出来不同的 Shapes,单态可以认为是这些对象可以被一个 Shapes 复用。
- 从 Object.assign 到 immutableJs 又回到解构新语法,层级如果不深的情况下解构语法可以代替 immutableJs 使用
- 两篇精读下需要重新考虑语法和上层引擎之间的关系,js 环境中
Object.assign()
优化效率比 ImmutableJs 要低一些,但是如果因为优化效率而增大开发项目打包体积,从而带来网络性能上的 RTT 增加,则需要思考和测试哪种优化方式更适合。