JS中反应式数据存储方案对比 Edata与RxJS, Mobx

简介: Javascript中的状态管理与监测其实一直都在正解决的路上,语言标准方面,从已废弃的[Object.observe API](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/observe),到进入到ES6标准的[Proxy](https://develope

Javascript中的状态管理与监测其实一直都在正解决的路上,语言标准方面,从已废弃的Object.observe API,到进入到ES6标准的Proxy,但都只针对单一对象状态监听,对多层对象实现监听只能借助于外部库,于是产生了我们常见的一些解决方案,如RxJS,提出了新的概念 Reactive Stream,即可被观测的事件流(observable event streams);另一个流行库Mobx则遵循Observer Pattern实现,另外还有一个叫Redux,基于CQRS实现。别说去应用,光是理解这些概念,开发者们都要先掉几根头发。

其实上面几种方案都是围绕着可被观测的对象(Observable Object)这一主题,除了上面几个流行库,在此强烈推荐一个新的更好的解决方案:edata

以下我们用代码来说明对比这几个状态管理库的核心用法:

RxJS observable

export class DataStore {
  public count: BehaviorSubject<number> = new BehaviorSubject(0);
  update(newValue: number) { this.count.next(newValue); }
}

export class ButtonComponent {
  public count: number;
  constructor(private dataStore: DataStore) {
    dataStore.count.subscribe(x => this.count = x);
  }
  onBtnClick() { this.dataStore.update(this.count + 1); }
}

上面的代码,我们在 DataStore 设定了一个可供订阅的 count,初始值为0。ButtonComponentconstructor 添加了一个对 count 的订阅(subscribe),并将变动会存到 this.count 里。按钮点击后触发 dataStore.update() 动作,让数据源中 count 加一,进而触发ButtonComponentthis.count 改变。

Mobx observable

export class DataStore {
  @observable public count: number;
  @action
  update(newValue: number) { this.count = newValue; }
}
export class ButtonComponent {
  public count: number;
  constructor(private dataStore: DataStore) {
    observe(dataStore, 'count', x => this.count = x.newValue);
  }
  onBtnClick() { this.dataStore.update(this.count + 1); }
}

Mobx使用 @observable 装饰器使对象可被观测,以及 @action 装饰器来定义反应式方法,非常直观。不过这里注意一下 observe() 这段代码,有两个坑:1)dataStore 必须为对象,若是 primitive value 必须要包在 observable.box() 中,增加了复杂度;2)count 值必须要变化才会触发,若改变的是同值,则不会触发!

为了演示 Mobx 这个问题,我们设定一个情景,我们加入 isDataLoading 变量表明是否数据是否已加载。

export class DataStore {
  @observable public data:number;
  @action
  update(newValue: number) { this.data = newValue; }
}
export class ButtonComponent {
  public data: number;
  public isDataLoading: boolean;
  constructor(private dataStore: DataStore) {
    observe(dataStore, 'data', x => {
      this.data = x.newValue;
      this.isDataLoading = false;
    });
  }
  onBtnClick() {
    this.isDataLoading = true;
    this.dataStore.update(this.data);
  }
}

这里会产生一个BUG,isDataLoading 一直为 true,因为 this.dataStore.update(this.data) 这句没有改变数值,导致 observe 并没有触发。解决方案就是使用 data = observable.box(),然后使用 data.set(value) 来进行数值设置。

另外还有一个坑,在 Mobx v4 中数组类型判断要非常注意:

var numbers = observable([1,2,3]);
Array.isArray(numbers)  // false ???
Array.isArray(numbers.slice())  // true !!!

简单对比 RxJSMobx,可以看出 RxJS 是比较经典的 pub/sub 模式实现,Mobx 更贴近于声明式 + callback风格,但也有不少坑来自于它本身的实现。

重点来了,

快速上手,不想了解太多概念,坑又少,扩展性好,推荐使用edata

我们来看下同样的例子,使用 edata 如何实现:

import {edataProxy} from 'edata'

export const dataStore = edataProxy({
    data: 0,
    update (newValue: number) {
        this.data = newValue
    }
})

export class ButtonComponent {
  public data: number;
  public isDataLoading: boolean;
  constructor(private dataStore: EdataProxy) {
    dataStore.__watch__('data', x => {
      this.data = x.data.value;
      this.isDataLoading = false;
    })
  }
  onBtnClick() {
    this.isDataLoading = true;
    this.dataStore.update(this.dataStore.data);
  }
}

上面的代码来类比 Mobx,可以看到并没有用到非标准的装饰器语法,更贴近原生,并且没有 Mobx 的那些坑。

这里要注意edataProxy()方法,它使得 dataStore 可以直接使用JS原生方法来存/取对象,但依赖于ES6 Proxy,若要支持IE浏览器,则尽量使用 edata的低阶API

更多edata介绍可以参考另一篇文章:JS中反应式数据存储方案对比 RxJS, Mobx 与 edata

这个库的作者当然也是本文的作者,也需要同学们来一起共建,方式包括但不限于:使用并提出建议,PR,Star,转发等。


badge 同学, 如果觉得本文对你有帮助, 欢迎打赏一杯咖啡~

qr
目录
相关文章
|
存储 JavaScript 前端开发
Vuex详解:Vue.js的状态管理方案
Vuex详解:Vue.js的状态管理方案
141 1
|
2月前
|
自然语言处理 JavaScript 前端开发
一文梳理JavaScript中常见的七大继承方案
该文章系统地概述了JavaScript中七种常见的继承模式,包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合继承等,并探讨了每种模式的实现方式及其优缺点。
一文梳理JavaScript中常见的七大继承方案
|
29天前
|
JavaScript 前端开发
原生js常见报错及其处理方案
原生js常见报错及其处理方案
18 0
|
3月前
|
存储 前端开发 JavaScript
揭秘!JavaScript本地存储的四大绝技:从Cookie到IndexedDB,让你的Web应用秒变数据存储高手,轻松应对各种挑战!
【8月更文挑战第4天】JavaScript为核心前端技术,提供多样本地存储方案以优化用户体验与减少服务器负载。首先,Cookie虽用于基本数据如登录状态,但受大小限制及安全性影响。接着,Web Storage中的LocalStorage持久存储不变数据,SessionStorage则限于单次会话。更进一步,IndexedDB作为全面数据库解决方案,支持复杂数据操作但使用较复杂。每种方式根据应用需求各有优势。
63 9
|
4月前
|
缓存 监控 JavaScript
常见的JS优化方案都有那些
【7月更文挑战第7天】 JavaScript优化包括代码优化(箭头函数、解构赋值、模板字面量、展开运算符、高阶函数)、DOM操作优化(减少操作、事件委托、节流防抖)、异步优化(Promise、Web Workers)、缓存策略(结果缓存、HTTP缓存)、压缩合并以及性能分析和监控。通过这些方法,提升网页性能和用户体验。
31 1
|
4月前
|
JavaScript 前端开发 数据可视化
js 实现动画的两种方案对比:setTimeout vs RAF (requestAnimationFrame)
js 实现动画的两种方案对比:setTimeout vs RAF (requestAnimationFrame)
70 2
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的共享单车数据存储系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的共享单车数据存储系统附带文章源码部署视频讲解等
49 1
|
4月前
|
前端开发
大屏自适应/适配方案【详解】(echarts自适配、rem、flexible.js、vscode中px2rem插件自动计算rem)
大屏自适应/适配方案【详解】(echarts自适配、rem、flexible.js、vscode中px2rem插件自动计算rem)
603 0
|
5月前
|
移动开发 JavaScript 前端开发
rem的适配方案,css文件和js文件的引入方式,特色小边框的制作,DS-Digital.ttf数字展示屏的使用方法:,自适应图片 background-size,jQuery爆bug,a和盒子居中,
rem的适配方案,css文件和js文件的引入方式,特色小边框的制作,DS-Digital.ttf数字展示屏的使用方法:,自适应图片 background-size,jQuery爆bug,a和盒子居中,
|
5月前
|
缓存 JavaScript 前端开发
程序员必知:广告等第三方应用嵌入到web页面方案之使用js片段
程序员必知:广告等第三方应用嵌入到web页面方案之使用js片段
71 0
下一篇
无影云桌面