美文网首页
Rudex源码剖析

Rudex源码剖析

作者: YQY_苑 | 来源:发表于2020-09-27 08:41 被阅读0次

    Redux官方代码库提供了以下几个模块文件:

    applyMiddleware.js
    bindActionCreators.js
    combineReducers.js
    compose.js
    createStore.js

    compose.js

    /**
     * Composes single-argument functions from right to left. The rightmost
     * function can take multiple arguments as it provides the signature for
     * the resulting composite function.
     *
     * @param {...Function} funcs The functions to compose.
     * @returns {Function} A function obtained by composing the argument functions
     * from right to left. For example, compose(f, g, h) is identical to doing
     * (...args) => f(g(h(...args))).
     */
    export default function compose(...funcs) {
        if (funcs.length ===0) {
            return arg => arg
        }
        if (funcs.length ===1) {
            return funcs[0]
        }
        return funcs.reduce((a, b) => (...args) => a(b(...args)))
    } 
    

    以上代码很好理解,当compose无参数时,返回一个空函数,参数为唯一函数时,直接将这个函数作为返回值,重点在于最后一部分:
    return funcs.reduce((a, b) => (...args) => a(b(...args)))

    对多个参数组合成的函数数组进行reduce操作,其实以上代码等同于:
    return funcs.reduceRight((composed, f) => f(composed));

    相当于对数组内的所有函数,从右至左,将前一个函数作为后一个函数的入口参数依次返回,比如compose(fn1,fn2,fn3)最后返回的结果应该是这样子的:
    fn1(fn2(fn3))

    bindActionCreators.js

    import warning from'./utils/warning'
    
    function bindActionCreator (actionCreator, dispatch) {
        return (...args) => dispatch(actionCreator(...args))
    }
    
    export default function bindActionCreators (actionCreators, dispatch) {
        if (typeof actionCreators ==='function') {
            return bindActionCreator(actionCreators, dispatch)
        }
        if (typeof actionCreators !=='object'|| actionCreators ===null) {
            throw new Error(`bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` + `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`)
        }
        const keys = Object.keys(actionCreators)
        const boundActionCreators ={}
        for (let i =0; i < keys.length; i++) {
            const key = keys[i]
            const actionCreator = actionCreators[key]
            if (typeof actionCreator ==='function') {
                boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
            } else {
                warning(`bindActionCreators expected a function actionCreator for key '${key}', instead received type '${typeof actionCreator}'.`)
            }
        }
        return boundActionCreators
    }
    

    对于单个actionCreator,代码很简单,直接返回一个被dispatch包裹过的action而已,对于多个actionCreators,如果入口参数是一个function,说明只提供了一个actionCreator,直接调用bindActionCreator(actionCreators,dispatch),对于以对象形式输入的多个actionCreators,对其遍历输出每一个bindActionCreator(actionCreators,dispatch)并封装在具有同名键值的boundActionCreators对象中,这样在我们需要调用action的地方直接boundActionCreators[actionCreate定义名]就可以了。

    createStore.js

    //用于校验是否是纯对象
    import isPlainObject from'lodash/isPlainObject'
    //内部私有属性,暂时不做扩展
    import $$observable from'symbol-observable'
    
    //内部action,用于调用所有reducers生成初始state
    export const ActionTypes ={INIT:'@@redux/INIT'}
    export default function createStore(reducer, preloadedState, enhancer) {
        if (typeof preloadedState ==='function' && typeof enhancer ==='undefined') {
            enhancer = preloadedState
            preloadedState = undefined
        }
        if (typeof enhancer !=='undefined') {
            if (typeof enhancer !=='function') {
                throw new Error('Expected the enhancer to be a function.')
            }
            //函数柯里化,enhancer提供增强版(中间件扩展)的store
            return enhancer(createStore)(reducer, preloadedState) 
        }
        //reducer必须是一个function
        if (typeof reducer !=='function') {
            throw new Error('Expected the reducer to be a function.')
        }
        //store内部私有变量(外部无法直接访问)
        let currentReducer = reducer
        let currentState = preloadedState
        let currentListeners = []
        let nextListeners = currentListeners
        let isDispatching = false
        //为下一阶段监听器快照提供备份
        function ensureCanMutateNextListeners () {
            if (nextListeners === currentListeners) {
                nextListeners = currentListeners.slice()
            }
        }
    
        //获取最新state
        function getState() {
            return currentState
        }
    
        //用于订阅state的更新
        function subscribe(listener) {
            if (typeof listener !=='function') {
                throw new Error('Expected listener to be a function.')
            }
            //保证只有第一次执行unsubscribe()才是有效的,只取消注册当前listener
            let isSubscribed =true
            //为每次订阅提供快照备份nextListeners,主要防止在遍历执行currentListeners回调
            //过程中触发了订阅/取消订阅功能,若直接更新currentListeners将造成当前循环体逻辑混乱
            //因此所有订阅/取消订阅的listeners都是在nextListeners中存储的,并不会影响当前的dispatch(action)
            ensureCanMutateNextListeners()
            nextListeners.push(listener)
            //返回一个取消订阅的函数
            return function unsubscribe() {
                //保证当前listener只被取消注册一次
                if (!isSubscribed) { return }
                isSubscribed =false
                ensureCanMutateNextListeners()
                const index = nextListeners.indexOf(listener)
                nextListeners.splice(index,1)
            }
        }
    
        function dispatch(action) {
            //保证dispatch是个纯对象,即字面量对象或Object创建的对象
            //这是因为原始版的dispatch只支持同步action,约定的格式是纯对象
            //可以使用中间件来dispatch扩展功能,增加action的类型种类
            if (!isPlainObject(action)) {
                throw new Error('Actions must be plain objects. '+'Use custom middleware for async actions.')
            }
            //action必须要有key为type的动作类型
            if (typeof action.type ==='undefined') {
                throw new Error('Actions may not have an undefined "type" property. '+'Have you misspelled a constant?')
            }
            //判断在执行dispatch的过程中是否已存在dispatch的执行流
            //保证dispatch中对应的reducer不允许有其他dispatch操作
            if (isDispatching) {
                throw new Error('Reducers may not dispatch actions.')
            }
            try {
                //根据提供的action,执行根reducer从而更新整颗状态树
                isDispatching = true
                currentState = currentReducer(currentState, action)
            } finally {
                isDispatching = false
            }
            //通知所有之前通过subscribe订阅state更新的回调listener
            const listeners = currentListeners = nextListeners
            for(let i =0; i < listeners.length; i++) {
                const listener = listeners[i]listener()
            }
            return action
        }
    
    
        //替换当前reducers,如从其他文件引入了新的reducers进行热加载
        function replaceReducer (nextReducer) {
            if (typeof nextReducer !=='function') {
                throw new Error('Expected the nextReducer to be a function.')
            }
        }
    
        function observable () {
            const outerSubscribe = subscribe
            return {
                subscribe (observer) {
                    if (typeof observer !=='object') {
                        throw new TypeError('Expected the observer to be an object.')
                    }
                
                    function observeState() {
                        if (observer.next) {
                            observer.next(getState())
                        }
                    }
                    observeState()
                    const unsubscribe = outerSubscribe(observeState)
                    return { unsubscribe }
                },
                [$$observable] () {
                    return this
                }
            }
        }
    
        dispatch({ type: ActionTypes.INIT })
        return {
            dispatch,
            subscribe,
            getState,
            replaceReducer,
            [$$observable]: observable
        }
    }
    

    一眼望去,还是有些懵逼的,但如果我们把它划分为以下三个部分分别理解或许就简单多了。

    • 入口参数:reducer、preloadState、enhancer
    • 内部变量:currentReducer、currentState、currentListeners、nextListeners、isDispatching
    • 输出:dispatch、subscribe、getState、replaceReducer

    相关文章

      网友评论

          本文标题:Rudex源码剖析

          本文链接:https://www.haomeiwen.com/subject/erjkuktx.html