带你从头到尾系统地撸一遍Redux源码(一)

简介: Redux 背后的Flux 架构思想看源码首先得明白,Redux背后的架构思想,为什么他和React那么的搭配,我们可以认为 Redux 是 Flux 的一种实现形式(虽然它并不严格遵循 Flux 的设定),理解 Flux 将帮助你更好地从抽象层面把握 Redux。首先flux架构将一个应用分成4个部分:view:  视图层action(动作):视图层发出的动作如: mouseclickdispatcher (派发器) :主要是用来接受actions,执行回调函数store(数据层):用来存放应用的状态,一旦发生变动就要提醒 view 视图层更新从图中可以看出Flux最大的

Redux 背后的Flux 架构思想



看源码首先得明白,Redux背后的架构思想,为什么他和React那么的搭配,我们可以认为 Redux 是 Flux 的一种实现形式(虽然它并不严格遵循 Flux 的设定),理解 Flux 将帮助你更好地从抽象层面把握 Redux。


首先flux架构将一个应用分成4个部分:


  1. view:  视图层


  1. action(动作):视图层发出的动作如: mouseclick


  1. dispatcher (派发器) :主要是用来接受actions,执行回调函数


  1. store(数据层):用来存放应用的状态,一旦发生变动就要提醒 view 视图层更新


image.png


从图中可以看出Flux最大的特点就是 ———— 单向数据流


  1. 用户访问view


  1. view发出用户的action


  1. dispatch 收到action, 则要求store 就行数据更新


  1. store 更新后 发出一个改变事件


  1. 接收到change视图更新


读到这里肯定就有人问? 就因为他这样所以我们要采用这种方式,因为前端项目有大多数是mvc 或者是mvvm架构。这种架构有什么缺点,有一个很大的缺点就是 当业务复杂度变得越来越高的时候,因为允许view 层和model层 直接传递。因为model可能不止对应一个view 层,就会出现下图这样的情况:



image.png


从图上看数据流这是真的混乱,如果项目中出现bug就很难定位到到底是哪一步出现问题,所以Flux 的核心是单向数据流, 因为视图更新就是从store通知视图更新。


Redux的架构其实是和Flux是非常像的:理解了Flux,自然理解了Redux, 毕竟整体的架构思想是非常像的。废话不多说吧,直接看图:


image.png


我给大家手动模拟下整个流程,用户点击鼠标发出一个action,经过Actions的处理,Actions 其实就是返回一个对象, 对象里面包含type 和所需要的数据 ,数据传到了Reducer 本质是一个纯函数,输入什么,输出什么,不做任何逻辑的运算。返回一个新的State之后,传递到数据中心Store,由Store通知视图更新。整个流程就结束了。那么Redux到底是怎么做到的,带着好奇心,我和大家一起撸一遍源码,看他里面到底有什么奥妙?


Redux源码解析



image.png


Redux 源码的目录结构十分简单, types 主要存放的是ts 定义的一些类型, utils主要是一些通用方法,没什么涉及关键流程的,所以接下来我就主要分析 applyMiddleware 、 combinReducers、compose、 createStrore这三个ts 文件

createStore作为Redux的开始 我们先分析这个文件


CreateStore



// 引入 redux
import { createStore } from 'redux'
// 创建 store  
const store = createStore(
    reducer,
    initial_state,
    applyMiddleware(middleware1, middleware2, ...)
); 
复制代码


从图中createStore 接受3个参数


  • 第一个参数就是一个reducer 一个纯函数 ,由我们自己定义


  • 第二个参数 初始化的数状态


  • 第三个参数 其实就是制定中间件 在源码中就是enhancer 增强store

从拿到入参到返回出 store 的过程中,到底都发生了什么呢?这里我为你提取了


createStore 中主体逻辑的源码(解析在注释里):


image.png



这段代码主要是做一些类型判断, 和一些写法兼容没什么。继续往下看, 下面是一些初始状态的赋值:


image.png



肯定有部分同学对这里的快照和浅拷贝确保不同的引用有疑问? 我这里先卖个关子,等整个流程走完后面重点分析why?? 接下来就进入我们经常用的getState函数了。


getState:


image.png


我草就这么几行代码,十分的简单,源码也就那样嘛,easy easy! 继续往下看


subscribe:


image.png


这里订阅的时候浅拷贝了一下,卸载的时候也浅拷贝,用的都是nextListeners, 还记得我们有个currentListeners吧, 难道说这个一点用都没有嘛。 我们接着往下看。


dispatch:


image.png


dispatch 的时候: 又将next 重新复制给 current 然后执行每个listenr.  看到这里我想你应该明白reducer 中 我dispatch ? 或者做一些subscribe  做一些脏操作,redux 源码中为了防止这种 就是设置 isDispatching 这个 变量来控制。


所以dispacth一个action? Redux 帮我们做了啥事, 就很简单2件事


  1. oldState 经过reducer 产生了newState, 更新了store数据中心


  1. 触发订阅


整个Redux 的工作流,到这里其实已经结束了, 但是我们还有一个疑问就是 subscribe 为啥都是nextListeners 然后在dispatch 的 又把值重新赋给currentListeners? 这是为什么呢??


答案就是:为了保证触发订阅的稳定性


这句话怎么理解呢我举一个例子:


// 定义监听函数a
function listenera() {
}
// 订阅 a,并获取 a 的解绑函数
const unSubscribea = store.subscribe(listenera)
// 定义监听函数 b
function listenerb() {
  // 在 b 中解绑 a
  unSubscribea()
}
// 定义监听函数 c
function listenerc() {
}
// 订阅 b
store.subscribe(listenerb)
// 订阅 c
store.subscribe(listenerc)
复制代码


从上文我可以得知当前的currentListeners:


[listenera, listenerb, listenerc]


但是比较特殊的是listenb 其实卸载 listena的, OK如果我们不浅拷贝一下, 那么触发订阅的时候数组遍历到 i = 2 的时候其实数组是undefined , 这样引发报错, 因为我们在 订阅前和卸载订阅都浅拷贝一下,nextListeners数据随便怎么变, 只要保证currentListener 稳定 就好了。


本次dispacth完之后,下一次dispacth 假设没有新增订阅,   数据关系又重新赋值。

listeners =( currentListeners = nextListeners)

你仔细回想一下这个变化,是不是所有就理解的通了, 这也是为什么Redux 订阅稳定的原因了啦。设计真的是十分的巧妙哇,读到现在发现源码其实并没有想象的辣么难? 细节处理满分哇。 接下来就是分析Redux的中间件模型。


相关文章
|
JavaScript 算法 索引
面试被问到vue的diff算法原理,我不允许你回答不上来
面试被问到vue的diff算法原理,我不允许你回答不上来
56 0
|
6月前
|
算法
二分查找算法的细节刨析 --适合有基础的朋友阅读
二分查找算法的细节刨析 --适合有基础的朋友阅读
|
11月前
|
C语言
近期一系列个人做题反复记不住以及思路不清晰问题的总结
近期一系列个人做题反复记不住以及思路不清晰问题的总结
50 0
|
缓存 移动开发 JavaScript
vue面试提整理偏原理
vue面试提整理偏原理
67 0
|
设计模式 人工智能 程序员
感觉自己的代码很乱?因为你不懂套路
编程教室开了这么久,已经有很多人从完全零基础的小白成为了会写代码的菜鸟程序员,能够自己独立开发程序。不过到此阶段,常常会遇到瓶颈,感觉功能可以实现
|
前端开发 自动驾驶 算法
这个知识点99%的前端都没有听过,不信你进来看?
这个知识点99%的前端都没有听过,不信你进来看?
103 0
|
存储
《操作系统概论》第一遍阅读
前言: 《操作系统概论》从操作系统实现资源管理的观点出发,产生如何对计算机系统中的软硬件资源进行管理,要求我们理解操作系统要做什么,怎么样去做。学习操作系统概论是在米老师给我们讲完《信息资源管理》学习后按照老师所讲的方法来学习的,所以这次阅读,都是按照老师的指导一步一脚一脚印完成的。感觉很好。
|
JavaScript 前端开发 程序员
做为前端面试官,春招跳槽建议你把这20个vue题目搞懂
做为前端面试官,春招跳槽建议你把这20个vue题目搞懂
124 0
|
存储 数据安全/隐私保护 Python
一文让你完全弄懂Stegosaurus(下)
一文让你完全弄懂Stegosaurus(下)
161 0
一文让你完全弄懂Stegosaurus(下)
|
缓存 Python
一文让你完全弄懂Stegosaurus(上)
一文让你完全弄懂Stegosaurus
188 0
一文让你完全弄懂Stegosaurus(上)