React 的多态性

1 引言

本周精读的文章是:surprising-polymorphism-in-react-applications,看看作者是如何解释这个多态性含义的。

读完文章才发现,文章标题改为 Redux 的多态性更妥当,因为整篇文章都在说 Redux,而 Redux 使用场景不局限于 React。

2 概述

Redux immutable 特性可能产生浏览器无法优化的性能问题,也就是浏览器无法做 shapes 优化,也就是上一篇精读《JS 引擎基础之 Shapes and Inline Caches》 里提到的。

先看看普通的 redux 的 reducer:

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, {
        completed: !state.completed
      });

    default:
      return state;
  }
};

我们简化一下使用场景,假设基于这个 reducer todo,生成了两个新 store s1 s2

const s1 = todo(
  {},
  {
    type: "ADD_TODO",
    id: 1,
    text: "Finish blog post"
  }
);

const s2 = todo(s1, {
  type: "TOGGLE_TODO",
  id: 1
});

看上去很常见,也的确如此,我们每次 dispatch 都会根据 reducer 生成新的 store 树,而且是一个新的对象。然而对 js 引擎而言,这样的代码可能做不了 Shapes 优化(关于 Shapes 优化建议阅读上一期精读 Shapes 优化),也就是最需要做优化的全局 store,在生成新 store 时无法被浏览器优化,这个问题很容易被忽视,但的确影响不小。

至于为什么会阻止 js 引擎的 shapes 优化,看下面的代码:

// transition-trees.js
let a = {x:1, y:2, z:3};

let b = {};
b.x = 1;
b.y = 2;
b.z = 3;

console.log("a is", a);
console.log("b is", b);
console.log("a and b have same map:", %HaveSameMap(a, b));

通过 node --allow-natives-syntax test.js 执行,通过调用 node 原生函数 %HaveSameMap 判断这种情况下 ab 是否共享一个 shape(v8 引擎的 Shape 实现称为 Map)。

结果是 false,也就是 js 引擎无法对 a b 做 Shapes 优化,这是因为 ab 对象初始化的方式不同。

同样,在 Redux 代码中常用的 Object.assign 也有这个问题:

image

因为新的对象以 {} 空对象作为最初状态,js 引擎会为新对象创建 Empty Shape,这与原对象的 Shape 一定不同。

顺带一提 es6 的解构语法也存在同样的问题,因为 babel 将解构最终解析为 Object.assign

image

对这种尴尬的情况,作者的建议是对所有对象赋值时都是用 Object.assign 以保证 js 引擎可以做 Shapes 优化:

let a = Object.assign({}, {x:1, y:2, z:3});

let b = Object.assign({}, a);

console.log("a is", a);
console.log("b is", b);
console.log("a and b have same map:", %HaveSameMap(a, b)); // true

3 精读

这篇文章需要与上一篇 精读《JS 引擎基础之 Shapes and Inline Caches》 连起来看容易理解。

作者描述的性能问题是引擎级别的 Shapes 优化问题,读过上篇精读就很容易知道,只有相同初始化方式的对象才被 js 引擎做优化,而 Redux 频繁生成的 immutable 全局 store 是否能被优化呢?答案是“往往不能”,因为 immutable 赋值问题,我们往往采用 Object.assign 或者解构方式赋值,这种方式产生的新对象与原对象的 Shape 不同,导致 Shape 无法复用。

这里解释一下疑惑,为什么说 immutable 对象之间也要优化呢?这不是两个不同的引用吗?这是因为 js 引擎级别的 Shapes 优化就是针对不同引用的对象,将对象的结构:Shape 与数据分离开,这样可以大幅优化存储效率,对数组也一样,上一篇精读有详细介绍。

所以笔者更推荐使用比如 immutable-js 这种库操作 immutable 对象,而不是 Object.assign,因为封装库内部是可能通过统一对象初始化方式利用 js 引擎进行优化的。

4 总结

原文提到的多态是指多个相同结构对象,被拆分成了多个 Shape;而单态是指这些对象可以被一个 Shape 复用。

笔者以前也经历过从 Object.assign 到 Immutablejs 库,最后又回到解构新语法的经历,觉得在层级不深情况下解构语法可以代替 Immutablejs 库。

通过最近两篇精读的分析,我们需要重新思考这样做带来的优缺点,因为在 js 环境中,Object.assign 的优化效率比 Immutablejs 库更低。

最后,也完全没必要现在就开始重构,因为这只是 js 运行环境中很小一部分影响因素,比如为了引入 Immutablejs 让你的网络延时增加了 100%?所以仅在有必要的时候优化它。

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=17678,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?