媒介
用 React + Redux 已一段时间了,记得刚开始用Redux 的时刻觉得非常绕,总搞不起内里的关联,假如人人用一段时间Redux又看了它的源码话,对你的明白会有很大的协助。看完后,在回来看Redux,有一种 柳暗花明又一村 的觉得 ,.
源码
我剖析的是用 es6 语法的源码,人人看目次组织,一共有 6 个问件。先说下各个文件也许功用。
applyMiddlewar.js
运用自定义的 middleware 来扩大 ReduxbindActionCreators.js
把 action creators 转成具有同名 keys 的对象,运用时能够直接挪用combineReducers.js
一个比较大的运用,须要对 reducer 函数 举行拆分,拆分后的每一块自力担任治理 state 的一部分compose.js
从右到左来组合多个函数,函数编程中常用到createStore.js
建立一个 Redux Store 来放一切的stateutils/warnimng.js
控制台输出一个正告,我们能够不必看
我会按每一个模块的重要性,去做剖析,本日就先把 createStore .js
分享给人人.
createStore.js
解释很细致,直接看解释就能够了
// 导入 lodash ,推断是不是是一般(plain)对象
import isPlainObject from 'lodash/isPlainObject'
//导入 symbol 范例的 observable (symbol范例的属性,是对象的私有属性)
import $$observable from 'symbol-observable'
/**
*定义 Redux Action 的初始化 type
*
*/
export var ActionTypes = {
INIT: '@@redux/INIT'
}
/**
* 建立一个Redux store来寄存运用一切的 state。运用中有且只要一个store
*
* @param {Function} reducer 是一个函数,吸收两个参数,分别是当前的 state 树和
* 要处置惩罚的 action,返回新的 state 树
*
* @param {any} 初始化时的state ,在运用中,你能够把服务端传来经由处置惩罚后的 state
*传给它。假如你运用 combineReducers 建立 reducer,它必需是一个一般对象,与传入
*的 keys 坚持一样的组织。不然,你能够自在传入任何 reducer 可明白的内容。
*
* @param {Function} enhancer 是一个组合的高阶函数,返回一个强化过的 store creator .
* 这与 middleware类似,它也许可你经由过程复合函数转变 store 接口。
*
* @returns {Store} 返回一个对象,给外部供应 dispatch, getState, subscribe, replaceReducer,
*/
export default function createStore(reducer, preloadedState, enhancer) {
//推断 preloadedState 是一个函数而且 enhancer 是未定义
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState // 把 preloadedState 赋值给 enhancer
preloadedState = undefined // 把 preloadedState 赋值为 undefined
}
//推断 enhancer 不是 undefined
if (typeof enhancer !== 'undefined') {
//推断 enhancer 不是一个函数
if (typeof enhancer !== 'function') {
//抛出一个非常 (enhancer 必需是一个函数)
throw new Error('Expected the enhancer to be a function.')
}
//挪用 enhancer ,返回一个新强化过的 store creator
return enhancer(createStore)(reducer, preloadedState)
}
//推断 reducer 不是一个函数
if (typeof reducer !== 'function') {
//抛出一个非常 (reducer 必需是一个函数)
throw new Error('Expected the reducer to be a function.')
}
var currentReducer = reducer //把 reducer 赋值给 currentReducer
var currentState = preloadedState //把 preloadedState 赋值给 currentState
var currentListeners = [] //初始化 listeners 数组
var nextListeners = currentListeners//nextListeners 和 currentListeners 指向同一个援用
var isDispatching = false //标记正在举行dispatch
/**
* 保留一份定阅快照
* @return {void}
*/
function ensureCanMutateNextListeners() {
//推断 nextListeners 和 currentListeners 是同一个援用
if (nextListeners === currentListeners) {
//经由过程数组的 slice 要领,复制出一个 listeners ,赋值给 nextListeners
nextListeners = currentListeners.slice()
}
}
/**
* 猎取 store 里的当前 state tree
*
* @returns {any} 返回运用中当前的state tree
*/
function getState() {
//当前的state tree
return currentState
}
/**
*
* 增加一个 listener . 当 dispatch action 的时刻实行,这时候 sate 已发作了一些变化,
* 你能够在 listener 函数挪用 getState() 要领猎取当前的 state
*
* 你能够在 listener 转变的时刻挪用 dispatch ,要注重
*
* 1. 定阅器(subscriptions) 在每次 dispatch() 挪用之前都邑保留一份快照。
* 当你在正在挪用监听器(listener)的时刻定阅(subscribe)或许去掉定阅(unsubscribe),
* 对当前的 dispatch() 不会有任何影响。然则关于下一次的 dispatch(),不管嵌套与否,
* 都邑运用定阅列内外近来的一次快照。
*
* 2. 定阅器不应当关注一切 state 的变化,在定阅器被挪用之前,每每因为嵌套的 dispatch()
* 致使 state 发作屡次的转变,我们应当保证一切的监听都注册在 dispath() 之前。
*
* @param {Function} 要监听的函数
* @returns {Function} 一个能够移除监听的函数
*/
function subscribe(listener) {
//推断 listener 不是一个函数
if (typeof listener !== 'function') {
//抛出一个非常 (listener 必需是一个函数)
throw new Error('Expected listener to be a function.')
}
//标记有定阅的 listener
var isSubscribed = true
//保留一份快照
ensureCanMutateNextListeners()
//增加一个定阅函数
nextListeners.push(listener)
//返回一个作废定阅的函数
return function unsubscribe() {
//推断没有定阅一个 listener
if (!isSubscribed) {
//挪用 unsubscribe 要领的时刻,直接 return
return
}
//标记如今没有一个定阅的 listener
isSubscribed = false
//保留一下定阅快照
ensureCanMutateNextListeners()
//找到当前的 listener
var index = nextListeners.indexOf(listener)
//移除当前的 listener
nextListeners.splice(index, 1)
}
}
/**
* dispath action。这是触发 state 变化的唯一门路。
*
* @param {Object} 一个一般(plain)的对象,对象当中必需有 type 属性
*
* @returns {Object} 返回 dispatch 的 action
*
* 注重: 假如你要用自定义的中间件, 它能够包装 `dispatch()`
* 返回一些别的东西,如( Promise )
*/
function dispatch(action) {
//推断 action 不是一般对象。也就是说该对象由 Object 组织函数建立
if (!isPlainObject(action)) {
//抛出一个非常(actions 必需是一个一般对象. 或许用自定义的中间件来处置惩罚异步 actions)
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
// 推断 action 对象的 type 属性即是 undefined
if (typeof action.type === 'undefined') {
//抛出一个非常
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
//推断 dispahch 正在运转,Reducer在处置惩罚的时刻又要实行 dispatch
if (isDispatching) {
//抛出一个非常(Reducer在处置惩罚的时刻不能 dispatch action)
throw new Error('Reducers may not dispatch actions.')
}
try {
//标记 dispatch 正在运转
isDispatching = true
//实行当前 Reducer 函数返回新的 state
currentState = currentReducer(currentState, action)
} finally { // (try catch) 终究会被实行的处所
//标记 dispatch 没有在运转
isDispatching = false
}
//一切的的监听函数赋值给 listeners
var listeners = currentListeners = nextListeners
//遍历一切的监听函数
for (var i = 0; i < listeners.length; i++) {
// 实行每一个监听函数
listeners[i]()
}
//返回传入的 action 对象
return action
}
/**
* 替代盘算 state 的 reducer。
*
* 这是一个高等 API。
* 只要在你须要完成代码分开,而且须要马上加载一些 reducer 的时刻才能够会用到它。
* 在完成 Redux 热加载机制的时刻也能够会用到。
*
* @param {Function} store 要用的下一个 reducer.
* @returns {void}
*/
function replaceReducer(nextReducer) {
//推断 nextReducer 不是一个函数
if (typeof nextReducer !== 'function') {
//抛出一个非常 (nextReducer必需是一个函数)
throw new Error('Expected the nextReducer to be a function.')
}
//当前传入的 nextReducer 赋值给 currentReducer
currentReducer = nextReducer
//挪用 dispatch 函数,传入默许的 action
dispatch({ type: ActionTypes.INIT })
}
/**
* 在 creatorStore 内部没有看到此要领的挪用
* (猜测 : 作者能够想用比较壮大,活泼的 observable 库替代如今的 publish subscribe)
*
* @returns {observable} 状况转变的时刻返回最小的 observable.
* 想要相识跟多关于 observable 库,发起看下
* https://github.com/zenparsing/es-observable (规范 es Observable)
*/
function observable() {
//定阅要领赋值给变量 outerSubscribe
var outerSubscribe = subscribe
return {
/**
* 这是一个最小的视察定阅要领
*
* @param {Object} 视察着的任何一个对象都能够作为一个 observer.
* 视察者应当有 `next` 要领
*/
subscribe(observer) {
//推断 observer 是一个对象
if (typeof observer !== 'object') {
//抛出非常
throw new TypeError('Expected the observer to be an object.')
}
//猎取视察着的状况
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
//返回一个作废定阅的要领
var unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
//对象的私有属性,临时不知道有什么用处
[$$observable]() {
return this
}
}
}
//reducer 返回其初始状况
//初始化 store 里的 state tree
dispatch({ type: ActionTypes.INIT })
//返回 store 暴漏出的接口
return {
dispatch, //唯一一个能够转变 state 的哈定时
subscribe, //定阅一个状况转变后,要触发的监听函数
getState, // 猎取 store 里的 state
replaceReducer, //Redux热加载的时刻能够替代 Reducer
[$$observable]: observable //对象的私有属性,供内部运用
}
}
结束语
代码已放在 githunb
上,人人能够检察 https://github.com/jiechud/redux-source-analyze , 假如对你有协助,麻烦请 Star
一下吧.