参考:https://juejin.im/post/5b627b...
参考:https://segmentfault.com/a/11...
前言
redux是什么?在Redux中文指南中是这样描述的:Redux是JavaScript状态容器,提供可预测的状态管理。为什么开始分析redux的源码呢?第一让自己更加深入的了解一波redux的原理和实现机制。第二就是redux源码比较少,比较容易理解。其他难的源码我也看不懂,嘻嘻。
MVC
为什么要要要在redux源码解析中提到MVC呢?主要是看到另外一个博主写的,感觉比较受用,所以借鉴过来了~
什么是MVC? MVC是一种设计模式,它将应用分为了三个部分,M(数据模型层,数据保存),V(视图层,用户界面),C(控制器层,业务逻辑)。
一个事件的发生可以理解成这样:
1.用户从view层和应用发起交互;
2.在控制器(controller)中的事件处理器被触发;
3.控制器从Modal层中请求数据,并交给view;
4.view层进行视图的展示;
借用一张图:
但是在实际项目中,例如backbone.js中的实现。虽然没有用过...看了下阮老师的MVC介绍中有这块,如图:
可以从图中看到:
1.view和model的双向箭头,view可以直接触发model的改变然后在视图展现;
2.用户可以直接触发controller(改变 URL 触发 hashChange 事件),然后controller直接发送给view;
这样在数据量庞大的前提下可能会出现以下情况(夸张情况):
既然是说要源码解析,那么我们首先看下源码结构~如下图:
applyMiddleware.js、bindActionCreator.js、combineReducer.js、compose.js、createStore.js这几个文件是redux中的核心文件也是核心的几个方法。我们来一个一个的看看。
1. createStore.js
createStore是干嘛的?
createStore接受3个参数:
reducer,是一个纯函数,这里不做多的解释。
preloadedState,可选参数,设置初始state,在同构应用中可以把服务端的state注水给他。
enhancer ,可选参数,是一个组合store的高阶函数,返回一个新的增强store,和middleware 相似,可以通过复合函数改变store接口。
createStore会创建一个store,存放所有的state,在应用中只有一个store。在创建store的时候会默认dispatch一个action。接下来上源码(经过简化的,但是重要的都留下了,嘻嘻):
import $$observable from 'symbol-observable'
import ActionTypes from './utils/actionTypes'
import isPlainObject from './utils/isPlainObject'
//createStore接受三个参数
export default function createStore(reducer, preloadedState, enhancer) {
//判断下preloadedState和enhancer是否存在
//然后将两个参数值交换的过程
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
//判断enhancer是否是函数类型,如果不是则抛出错误
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
//将createStore当做参数传入通过包装返回,然后再执行无enhancer的createStore方法
return enhancer(createStore)(reducer, preloadedState)
}
//对reducer进行类型判断,如果不是函数类型抛出异常
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
//这里定义了当前的reducer
let currentReducer = reducer
//这里定义了当前的state,然后将初始的state赋值
let currentState = preloadedState
//定义一个数组存放一组监听函数,当state改变后触发,
let currentListeners = []
// 这一步干啥的?????还不懂,留着问题,继续往下看!!!
let nextListeners = currentListeners
//应该是用来判断是否正在执行dispatch,有啥用????留着问题,还是继续往下看!!!
let isDispatching = false
//靠,这又是干啥的,感觉和state改变后的监听函数有关系,还是放着吧!!!回头再看
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
//通过slice方法创建一个副本然后赋值给nextListeners
nextListeners = currentListeners.slice()
}
}
//哦,这个知道,store有一个getState方法,用来获取当前的state。
function getState() {
//这里做下判断,如果在dispatching则抛出异常
if (isDispatching) {
throw new Error(
'You may not call store.getState() while the reducer is executing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'
)
}
//这里就是返回当前的state了
return currentState
}
//store的subscribe方法,添加一个listener监听函数,用来监听state改变的回调。
function subscribe(listener) {
//首先判断是否是函数类型,如果不是则抛出异常
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
//然后判断是否在dispatch,如果是则抛出异常,如果在subscribe中再出发dispatch就容易
//产生死循环
if (isDispatching) {
throw new Error(
'You may not call store.subscribe() while the reducer is executing. ' +
'If you would like to be notified after the store has been updated, subscribe from a ' +
'component and invoke store.getState() in the callback to access the latest state. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
//感觉是用来标记啥的,等会瞅瞅!!!(回头看原来是用来标识是否有订阅listener)
let isSubscribed = true
//咦。这不是我们在上面看到的一个函数么,它在这里干啥啊?
//滚动你的鼠标上去看看它的函数体里有啥?
//哦哦,它是把监听的函数列表保存了一个快照哎;
ensureCanMutateNextListeners()
//然后在这里给监听函数快照中添加新的监听函数。
nextListeners.push(listener)
//返回一个取消订阅的函数
return function unsubscribe() {
//咦,看到这个isSubscribed了,原来是在取消监听函数中使用,
//通过isSubscribed判断是否订阅了listener,上面isSubscribed
//在刚进来的时候就标记为true
if (!isSubscribed) {
return
}
//判断是否在dispatch,如果在则抛出异常
if (isDispatching) {
throw new Error(
'You may not unsubscribe from a store listener while the reducer is executing. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
//将isSubscribed设置false表示没有订阅的listener了
isSubscribed = false
//这里又要保存一个副本
ensureCanMutateNextListeners()
//找到当前的listener,然后删掉~~~
//是不是看到这里感觉nextListeners和currentListeners有啥用有点疑问,
//下面是redux文档上关于subsribe的描述,应该可以理解了
/**
* 1.监听器调用 dispatch() 仅仅应当发生在响应用户的 actions 或者特殊的条件限制下(比如: 在 store 有一个特殊的字段时 dispatch action)。虽然没有任何条件去调用 dispatch() 在技术上是可行的,但是随着每次 dispatch() 改变 store 可能会导致陷入无穷的循环。
* 2.订阅器(subscriptions) 在每次 dispatch() 调用之前都会保存一份快照。当你在正在调用监听器(listener)的时候订阅(subscribe)或者去掉订阅(unsubscribe),对当前的 dispatch() 不会有任何影响。但是对于下一次的 dispatch(),无论嵌套与否,都会使用订阅列表里最近的一次快照。
* 3.订阅器不应该注意到所有 state 的变化,在订阅器被调用之前,往往由于嵌套的 dispatch() 导致 state 发生多次的改变。保证所有的监听器都注册在 dispatch() 启动之前,这样,在调用监听器的时候就会传入监听器所存在时间里最新的一次 state。
*/
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
//这里是dispatch
function dispatch(action) {
//判断 action 不是普通对象。也就是说该对象由 Object 构造函数创建
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
//action对象必传一个type
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
//判断 dispahch 正在运行,Reducer在处理的时候又要执行 dispatc
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
//执行当前 Reducer 函数返回新的 state
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
//循环执行listeners
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
//最后返回一个action对象
return action
}
//初始化 store,默认执行dispatch
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。