Immutable?Mutative 比 Immer.js 快 10x 倍?

家好,很高兴又见面了,我是"高级前端‬进阶‬",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

高级前端‬进阶

1.什么是不可变性(Immutable Data)?

Immutable Data 一旦创建,就不能被更改。对 Immutable 对象的任何修改、添加或删除操作都会返回一个新的 Immutable 对象。

什么是不可变对象?图片来源:Alamy Stock Photo

Immutable 实现原理是持久化数据结构(Persistent Data Structure),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。

为了避免深度拷贝(deep Copy)把所有节点都复制一遍带来的性能损耗,Immutable 使用了共享结构(Structural Sharing),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。如下动图所示:

2.Immer介绍?

2.1 什么是Immer?

Immer 简化了不可变数据结构的处理。

Immer 可用于任何需要使用不可变数据结构的上下文。 例如与 React state、React 或 Redux reducer 或配置管理相结合。 不可变数据结构允许更改检测:如果对对象的引用没有更改,则对象本身没有更改。 此外,它使克隆更加容易:不需要复制数据树的未更改部分,并且在内存中与相同状态的旧版本共享。

const updatedUser = {
    ...User,
  // Rest展开操作User来获取新的更新后的User对象,即updatedUser
    ed: {
        ...User.ed,
        school : {
          ...User.ed.school,
          name: 'B'
        }
    }
}

一般来说,这些好处可以通过确保您永远不会更改对象、数组或映射的任何属性,而是始终创建一个更改的副本来实现。 在实践中,这会导致代码编写起来非常麻烦,而且很容易意外地违反这些约束。

Immer 将通过解决这些痛点帮助您遵循不可变数据范式:

2.2 Immer如何工作?

使用 Immer,会将所有更改应用到临时草稿,它是 currentState 的代理。 完成所有更新后,Immer 将根据对草案状态的改变生成 nextState。 这意味着可以通过简单地修改数据来与数据交互,同时保留不可变数据的所有好处。

使用 Immer 就像拥有一个私人助理。 助理拿了一封信(当前状态)并给了您一份副本(草稿)以记下更改。 完成后,助手会拿走你的草稿并为你生成最终的一封信(下一个状态)。

2.3 Immer使用?

const baseState = [
    // 基础、原始state
    {
        title: "Learn TypeScript",
        done: true
    },{
        title: "Try Immer",
        done: false
    }
]

假设有上面的基本状态,需要更新第二个待办事项,并添加第三个,同时不想改变原始的 baseState,同时‬避免深度克隆(以保留第一个待办事项)。

2.3.1 不使用Immer

如果没有 Immer,将不得不小心地浅复制受更改影响的状态结构的每一层。

const nextState = baseState.slice(
  // 数组浅复制
nextState[1] = {
    // replace element 1...
    ...nextState[1], // with a shallow clone of element 1
    done: true // ...combined with the desired update
}
// nextState被深度拷贝,push方法是安全的 
// but doing the same thing at any arbitrary time in the future would
// violate the immutability principles and introduce a bug!
nextState.push({title: "Tweet about it"})

2.3.2 使用Immer

使用 Immer,此过程更加直接。 可以利用 produce 函数,它将开始的状态作为第一个参数传递。 produce 将负责所有的复制操作,并通过冻结数据来防止未来的意外修改。

import produce from "immer"
const nextState = produce(baseState, draft => {
  // 通过produce方法操作
    draft[1].done = true
    draft.push({title: "Tweet about it"})
})

3.什么是Mutative?

Mutative是‬一个用于高效、不可变更新的 JavaScript 库,默认情况下比 Immer 快 10 倍,甚至比纯手工制作的 reducer 还要快。

4.为什么需要Mutative?

手动编写immutable更新通常很困难,且易出错。 Immer可以使用“可变”逻辑编写更简单的不可变更新。

但它的性能问题会导致运行时性能开销。 Immer 必须默认启用自动冻结(如果禁用自动冻结,性能会更差),Immer 的这种不可变状态并不常见。 跨进程、远程数据传输等场景不得不不断地冻结这些不可变数据。

Mutative还有很多的改进,比如更好的类型推断、非侵入式标记、支持更多类型的不变性、更安全等等。

5.Mutative vs Immer性能比较

测量(操作/秒)以更新 50K 数组和 1K 对象为例,具体代码查看文末资料。

Naive handcrafted reducer - No Freeze x 3,713 ops/sec ±0.86% (89 runs sampled)
Mutative - No Freeze x 5,323 ops/sec ±1.69% (93 runs sampled)
Immer - No Freeze x 8 ops/sec ±0.88% (23 runs sampled)
Mutative - Freeze x 875 ops/sec ±1.20% (95 runs sampled)
Immer - Freeze x 320 ops/sec ±0.45% (92 runs sampled)
Mutative - Patches and No Freeze x 752 ops/sec ±0.16% (96 runs sampled)
Immer - Patches and No Freeze x 7 ops/sec ±1.32% (23 runs sampled)
Mutative - Patches and Freeze x 425 ops/sec ±0.33% (95 runs sampled)
Immer - Patches and Freeze x 239 ops/sec ±0.99% (89 runs sampled)
The fastest method is Mutative - No Freeze

运行 yarn benchmark 。

操作系统:macOS 12.6,CPU:Apple M1 Max,Node.js:16.14.2

Immer 依赖于自动冻结,如果禁用自动冻结,Immer 将有巨大的性能下降,此时Mutative 有巨大的性能领先。尤其是对于大型数据结构,Mutative将有超过 50 倍的性能领先。

因此,如果使用 Immer,则必须启用自动冻结以提高性能。 Mutative 允许默认禁用自动冻结。 使用两者的默认配置,可以看到 Mutative(5,323 ops/sec)和 Immer(320 ops/sec)之间明显的性能差距。

总体而言,Mutative 在更多的性能测试场景中比 Immer 有巨大的性能领先。

6.Mutative特点和优势

7.Mutative 和 Immer 之间的区别

差别可以通过下面的图进行说明:

Mutative 和 Immer 之间的区别

除了上图的差异外,Mutative 比 Immer 有更少的错误, 经过混淆和 Gzip 压缩后,Mutative大小为 4.16KB,而具有相同功能的 Immer 大小为 4.67 KB。

8.Mutative安装&使用

8.1 安装

yarn install mutative 
//npm install mutative

8.2 使用


import { create } from 'mutative';
const baseState = {
  foo: 'bar',
  list: [{ text: 'coding' }],
};
// baseState代表基础state
const state = create(baseState, (draft) => {
  draft.foo = 'foobar';
  // 作为draf传递给第二个draf函数,修改后返回新的状态
  draft.list.push({ text: 'learning' });
});

9.本文总结

本文主要和大家介绍下 Mutative 和 Immer ,同时做了简单的对比。因为笔者也没有在生产项目中使用过Mutative 和 Immer,所以很多探索也就浅尝辄止,但是文末的参考资料提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。


参考资料

https://blog.csdn.net/JiaPeng366/article/details/106455221/

https://dev.to/unadlib/mutative-10x-faster-than-immer-2060

https://github.com/unadlib/mutative/blob/main/test/performance/benchmark.t

https://github.com/unadlib/mutative

https://immerjs.github.io/immer/

展开阅读全文

页面更新:2024-05-08

标签:数据结构   数组   草稿   副本   节点   对象   性能   状态   操作   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top