Skip to content

Latest commit

 

History

History
97 lines (66 loc) · 4.27 KB

63.精读《Redux的多态性》.md

File metadata and controls

97 lines (66 loc) · 4.27 KB

63.精读《React 的多态性》

本文的 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()

      • babel转译

      • 对于这种无法优化的情况,建议所有对象赋值的时候使用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 引擎层面上进行优化的。

summary

  • 原文多态(polymorphic)其实是多个相同结构的对象,拆分出来不同的 Shapes,单态可以认为是这些对象可以被一个 Shapes 复用。
  • 从 Object.assign 到 immutableJs 又回到解构新语法,层级如果不深的情况下解构语法可以代替 immutableJs 使用
  • 两篇精读下需要重新考虑语法和上层引擎之间的关系,js 环境中Object.assign() 优化效率比 ImmutableJs 要低一些,但是如果因为优化效率而增大开发项目打包体积,从而带来网络性能上的 RTT 增加,则需要思考和测试哪种优化方式更适合。