Vuex 源码还有一些缺陷?

我看了vuex3和vuex4的源码也输出了文章,看到这篇时,vuex还有缺陷?看了看确实是好文,不愧是大佬写的。文章不算长,推荐给大家看看。

点击下方卡片关注我、加个星标
学习源码整体架构系列、年度总结、JS基础系列


众所周知,Vuex 是 Flux 架构的一种实现。Flux 清晰确立了数据管理场景下各种职能单位,其主要准则有:

  1. 中心化状态管理

  2. 状态只能通过专门 突变 单元进行变更

  3. 应用层通过发送信号(一般称 action),触发变更

Vuex 也是紧紧围绕这些准则开发的,通过 store 类提供 Flux 模式的核心功能。在满足架构的基本要求之外,则进一步设计了许多便利的措施:

  1. 通过“模块化”设计,隔离数据单元

  2. 提供 getter 机制,提高代码复用性

  3. 使用 Vue.$watch 方法,实现数据流

  4. 零配置,天然整合进 Vue 环境

网上已经有很多解析的文章,没必要赘述。本文仅就 中心化、信号机制、数据流 三个点的实现上展开,讨论一下 Vuex 实现上的缺陷。

中心化

在Vuex中,store 整合了所有功能,是对外提供的主要接口,也是Flux模式下的数据管理中心。通过它,Vuex 主要对外提供了:

  • 信号相关的: dispatch、commit

  • 侦听器接口: subscribe

  • state 值变更接口(替换state值,不应调用): replaceState

  • state 模型变更接口(建议仅在按需引用场景下使用):registerModule、unregisterModule

  • 热更新接口(HMR逻辑,不关注):hotUpdate

官方实现的 store 非常复杂,耦合了许多逻辑。简便起见,我们刨除各种旁路逻辑,只关注Flux架构的中心化信号控制机制,可以总结出一份非常简单的实现:

export default class Store {constructor(options) {this._state = options.state;this._mutations = options.mutations;}get state() {return this._state;}commit(type, payload) {this._mutations[type].apply(this, [this.state].concat([...payload]));}
}

这是理解 Vuex 的核心,整份代码只有两个逻辑:

  1. 通过_state属性实现中心化、自包含数据中心层。

  2. 通过 dispatch 方法,回调触发事先注册的_mutations方法。

这份代码有很多问题,举例来说:

  • 使用简单对象作为 state

  • 状态的突变仅仅通过修改state对象属性值实现

  • 没有任何有效的机制,防止 state 对象被误修改

这些设计问题,在Vuex中同样存在,这与Vue.$watch机制有非常密切的关系(见下文),个人认为这是极其不严谨的。

信号机制

Vuex 提供了两个与信号有关的接口,其源码可简略为:

export default class Store {...commit (_type, _payload, _options) {...const entry = this._mutations[type]this._withCommit(() => {entry.forEach(function commitIterator (handler) {handler(payload)})})this._subscribers.forEach(sub => sub(mutation, this.state))...}dispatch (_type, _payload) {...const entry = this._actions[type]return entry.length > 1? Promise.all(entry.map(handler => handler(payload))): entry[0](payload)}...
}

两者之间的不同在于:

  1. dispatch 触发的是 action 回调;commit 触发的 mutation 回调。

  2. dispatch 返回 Promise;commit 无返回值。

这样的设计意图,主要还是职责分离,action 单元用于描述 发生了什么;mutation用于修改数据层状态state。Vuex 用相似的接口,将两者放置在相同的地位上,这一层接口设计其实存在弊病:

  1. action、mutation 各自需要一套type体系

  2. 允许应用层绕过action,直接 commit mutation

  3. state 并非 immutable 的,而且在 action 中允许修改 state

虽然确实提升了便利性,但对初学者而言,可能导致如下反模式:

  • 设计了两套无法正交的type体系

  • 造成“直接提交mutation即可”的假象,破坏了Flux的信号机制

  • 在 action 中手误修改了 state ,而没有友好的跟踪机制(这一点在getter中特别严重)

由于没有确切有效的机制防止错误,在使用Vuex的过程中,需要非常非常警惕;需要严谨正确地使用各种职能单元;或者以规范填补设计上的缺陷。

单向数据流

这里的数据流是指从 Vuex 的 state 到 Vue 组件的props/computed/data 等状态单元的映射,即如何在组件中获取state。Vuex 官方推荐使用 mapGetter、mapState 接口实现数据绑定。

mapState

该函数非常简单,代码逻辑可梳理为:

export const mapState = normalizeNamespace((namespace, states) => {const res = {}...normalizeMap(states).forEach(({ key, val }) => {res[key] = function mappedState() {...return typeof val === 'function' ?val.call(this, state, getters) :state[val]}})...return res
})

mapState 直接读取 state 对象的属性。值得注意的一点是,res[key]一般作为函数挂载在外部对象,此时函数的this指向挂载的 Vue 组件。

mapGetter

该函数同样非常简单,其代码逻辑为:

export const mapGetters = normalizeNamespace((namespace, getters) => {const res = {}normalizeMap(getters).forEach(({ key, val }) => {res[key] = function mappedGetter() {...return this.$store.getters[val]}...})return res
})

mapGetter 访问的则是组件挂载是 $store 实例的 getters 属性。

从 state 到 getter

Vuex 的 getter属性 与 Vue 的computed属性在各方面的特性都非常相似,实际上,getter 正是基于 computed 实现的。其核心逻辑有:

function resetStoreVM(store, state, hot) {...store.getters = {}const wrappedGetters = store._wrappedGettersconst computed = {}// 遍历 getter 配置,生成 computed 属性forEachValue(wrappedGetters, (fn, key) => {computed[key] = () => fn(store)Object.defineProperty(store.getters, key, {// 获取 vue 实例属性get: () => store._vm[key],enumerable: true // for local getters})})// 新建 Vue 实例,专门用于监听属性变更store._vm = new Vue({data: {?state: state},computed})...
}

从代码可以看出,Vuex 将整个 state 对象托管到vue实例的data属性中,以此换取Vue的整个 watch 机制。而getter属性正是通过返回实例的 computed 属性实现的,这种实现方式,不可谓不精妙。问题则是:

  1. Vuex 与 Vue 深度耦合,致使不能迁移到其他环境下使用

  2. Vue 的watch机制是基于属性读写函数实现的,如果直接替换根节点,会导致各种子属性回调失效,即不可能实现immutable特性

后语

Vuex 给我最大的感觉是:便利,同样的功能有各种不同语义的逻辑单元处理,职责分离方面做的非常好,如果严格遵循规范的话,确实能非常好的组织代码;接口也很简明易懂,对开发者非常友好。从用户数量、影响力等方面来看,无疑是一个非常伟大的框架。这里提出来的一些观点当然也是见仁见智的,目的不外乎抛砖引玉而已。


最近组建了一个湖南人的前端交流群,如果你是湖南人可以加我微信 ruochuan12 拉你进群。


今日话题

湖南长沙互联网据说发展还可以,所以建一个湖南人的前端交流群,欢迎湖南人进群。欢迎分享、收藏、点赞、在看我的公众号文章~

一个愿景是帮助5年内前端人走向前列的公众号

可加我个人微信 ruochuan12,长期交流学习

推荐阅读

我在阿里招前端,我该怎么帮你(可进模拟面试群)

2年前端经验,做的项目没技术含量,怎么办?

点击方卡片关注我、加个星标

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》多篇,在知乎、掘金收获超百万阅读。

从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。

同时,活跃在知乎@若川,掘金@若川。致力于分享前端开发经验,愿景:帮助5年内前端人走向前列。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三级菜单页面布局_三级菜单的最快导航布局

三级菜单页面布局重点 (Top highlight)When users navigate an interface, there’s a need for speed. The faster it is for them to find what they’re looking for, the more time they’ll save on their task.用户导航界面时,需要提高速度。 他们找到所需内容…

ux体验网站 英国_定义网站图像时的UX注意事项

ux体验网站 英国As the saying goes —俗话说 - “A picture is worth a thousand words.”“一张图片胜过千言万语。” When creating content on the web, it’s often recommended to be using high-quality imageries and making sure that the images serve its purpose …

iconfont 支持全新的彩色字体图标

大家好,我是若川。iconfont我相信大家都用过,而现在支持全新的彩色字体图标了。这是第二次转载,上一次的好文是2020 前端技术发展回顾。点击下方卡片关注我、加个星标学习源码整体架构系列、年度总结、JS基础系列一直以来,Web 中想…

出色的社区网站_《最后的我们》中出色的制作系统

出色的社区网站游戏设计分析 (GAME DESIGN ANALYSIS) The Last of Us became an instant classic the day it was released, back in 2013. At the sunset of the sixth console generation, it felt like Naughty Dog managed to raise the bar in all critical areas of game…

入坑 Electron 开发跨平台桌面应用

‍作为一个跨平台的桌面应用开发框架,Electron 的迷人之处在于,它是建立在 Chromium 和 Node.js 之上的 —— 二位分工明确,一个负责界面,一个负责背后的逻辑,典型的「你负责貌美如花,我负责赚钱养家」。上…

java 接口编程_JAVA面向接口编程

一、什么是面向接口编程要正确地使用Java语言进行面向对象的编程,从而提高程序的复用性,增加程序的可维护性、可扩展性,就必须是面向接口的编程。面向接口的编程就意味着:开发系统时,主体构架使用接口,接口…

小程序 显示细线_精心设计:高密度显示器上的细线

小程序 显示细线Despite the many benefits of Retina displays, there is one clear drawback that must be considered when designing for high-density screens:尽管Retina显示器具有许多优点,但在设计高密度屏幕时仍必须考虑一个明显的缺点: 必须避…

React 入门手册

大家好,我是若川。推荐这篇可收藏的React入门手册。也推荐之前一篇类似的文章《如何使用 React 和 React Hooks 创建一个天气应用》。点击下方卡片关注我、加个星标React 是目前为止最受欢迎的 JavaScript 框架之一,而且我相信它也是目前最好用的开发工具…

根号 巴比伦_建立巴比伦卫生设计系统

根号 巴比伦重点 (Top highlight)In this post I’ll explain the first phase of creating our Babylon DNA, the design system for Babylon Health, and how we moved the Babylon design team from Sketch to Figma.在这篇文章中,我将解释创建巴比伦DNA的第一阶…

《Migrating to Cloud-Native Application Architectures》学习笔记之Chapter 2. Changes Needed

2019独角兽企业重金招聘Python工程师标准>>> Cultural Change 文化变革 A great deal of the changes necessary for enterprise IT shops to adopt cloud-native architectures will not be technical at all. They will be cultural and organizational changes t…

前端,你要知道的SEO知识

大家好,我是若川。三天假期总是那么短暂,明天就要上班了。今天推荐一篇相对简单的文章。点击下方卡片关注我、加个星标之前有同学在前端技术分享时提到了SEO,另一同学问我SEO是什么,我当时非常诧异,作为前端应该对SEO很…

高安全性同态加密算法_坏的同态性教程

高安全性同态加密算法I was going to write at length about the issues I see in neumorphism and why this trend should be avoided. I know any attempt to guide my most impressionable colleagues away from it, will end up being failing because this fad is going t…

前端容易忽略的 debugger 调试技巧

大家好,我是若川。我们日常开发碰到的很多问题,通过 debugger 都能快速定位问题,所以推荐这篇大家容易忽略的调试技巧。会定位问题,可以节省很多时间。也就是我经常说的工欲善其事,必先利其器。也是为什么我经常强调调…

Spring高级程序设计这本书怎么样

关于Spring高级程序设计 评论读后感:这本书需要有一定的spring基础的人看读后感:对于了解Spring 很有用,并且是一本不错的参考书读后感:这本书早就想买了,就是太贵了~~~ 啦啦啦&…

玉伯:开源有带给我什么

在2021年527蚂蚁技术日上,蚂蚁内源社区举办了内源专场,在专场上玉伯给大家分享了《开源有带给我什么》,以下为演讲的图文整理。我的开源之路我从2009年到2018年,接近十年时间,一直在做开源的一些事情,在这个…

python并行运算库_最佳并行绘图Python库简介:“ HiPlot”

python并行运算库HiPlot is Facebook’s Python library to support visualization of high-dimensional data table, released this January. It is particularly well known for its sophisticated interactive parallel plot.HiPlot是Facebook的Python库,用于支持…

Asp.net 文件上传的 FileUpload FileName 和 FileUpload PostedFile.FileName的细节问题

Asp.net 文件上传的 FileUpload FileName 和 FileUpload PostedFile.FileName的细节问题 ASP.NET 文件上传估计大家都用得很熟悉,常用控件 FileUpload 。 主要步骤: 1.判断是否合法 2.获得文件的路径 (包括目录的完整路径,同时可能…

【赠书福利】不扶好眼镜,请别打开这本挑战JS语言特性的书

文末赠福利大家好,我是若川。为感谢大家一直以来的支持和肯定,文末抽《JavaScript悟道》3本包邮送和若干红包,详细规则请看文末哦。"人们不停地给老化的语言“整容”,拼命地往其中注入各种新的特性来稳住其流行地位&#xff…

我在工作中是如何使用Git的

大家好,我是若川。今天分享一篇关于git的好文章。我自己经常用命令行终端和git缩写。具体可以看我以往的文章。使用 ohmyzsh 打造 windows、ubuntu、mac 系统高效终端命令行工具,用过都说好。点击下方卡片关注我、加个星标学习源码整体架构系列、年度总结…

克服浮躁_设计思维:您克服并赢得低迷的最终工具。

克服浮躁设计思维101 (Design thinking 101) Let’s begin by getting ourselves clear on the question: What is design thinking?让我们首先弄清楚问题:设计思想是什么? Many people have an impression that design thinking has something to do …