kredux.js createStore实现 和 applyMiddleware 实现

    1. export function createStore(reducer,enhancer) {
    2. //如果存在enhancer
    3. if(enhancer) {
    4. return enhancer(createStore)(reducer)
    5. }
    6. let currentState = undefined;
    7. const currentListeners = []; //回调函数数组
    8. function getState() {
    9. return currentState;
    10. };
    11. //更新状态
    12. function dispatch(action) {
    13. //修改
    14. currentState = reducer(currentState,action)
    15. //变更通知
    16. currentListeners.forEach(v=>v())
    17. return action;
    18. }
    19. function subscribe(cb) {
    20. currentListeners.push(cb);
    21. };
    22. //初始化状态
    23. dispatch({type: '@IMOCKKDEDDSDE'})
    24. return {
    25. getState,dispatch,subscribe
    26. }
    27. };
    28. export function applyMiddleware(...middlewares) {
    29. return createStore => (...args) => {
    30. // 先完成之前的 createStore 工作
    31. // debugger
    32. const store = createStore(...args);
    33. // 原先的 dispatch
    34. let dispatch = store.dispatch;
    35. // 传递给中间件函数的参数
    36. const midApi = {
    37. getState: store.getState,
    38. dispatch: (...args) => dispatch(...args),
    39. }
    40. //将来中间件函数签名如下 : function({}) {}
    41. // debugger
    42. const chain = middlewares.map(mw => mw(midApi));
    43. // 强化dispatch, 让他可以循序执行中间件函数
    44. dispatch = compose(...chain)(store.dispatch);
    45. //返回全新store, 仅更新强化过的dispatch
    46. return {
    47. ...store,
    48. dispatch
    49. }
    50. }
    51. }
    52. export function compose(...funcs) {
    53. // debugger
    54. if(funcs.length === 0) {
    55. return arg=>arg;
    56. }
    57. if(funcs.length === 1) {
    58. return funcs[0];
    59. }
    60. // 聚合函数数组为一个函数 [fn1,fn2] = fn2(fn1())
    61. return funcs.reduce((left,right)=>(...args)=>right(left(...args)))
    62. }

    测试代码

    1. import React, { Component } from 'react'
    2. import {CreateStore, applyMiddleware} from './kredux';
    3. const counterReducer = function(state=1,action) {
    4. switch (action.type) {
    5. case 'add':
    6. return state +1;
    7. case 'minus':
    8. return state - 1;
    9. default:
    10. return state
    11. }
    12. }
    13. //自定义logger中间件
    14. function logger() {
    15. return dispatch=>action=> {
    16. console.log(action.type+'我执行啦')
    17. return dispatch(action)
    18. }
    19. }
    20. // 换种写法
    21. const thunk = ({dispatch,getState})=>dispatch=>action=>{
    22. if(typeof action === 'function') {
    23. action(dispatch,getState)
    24. }
    25. return dispatch(action)
    26. }
    27. const store = CreateStore(counterReducer,applyMiddleware(logger,thunk))
    28. export default class MyTestRedux extends Component {
    29. componentDidMount() {
    30. store.subscribe(()=>this.forceUpdate())
    31. }
    32. render () {
    33. return (
    34. <div>
    35. <h3>测试</h3>
    36. <h5>{store.getState()}</h5>
    37. <button onClick = {()=>store.dispatch({type:'add'})}>加一下</button>
    38. <button onClick = {()=>store.dispatch({type:'minus'})}>减一下</button>
    39. <button onClick = {()=>store.dispatch(function(){
    40. setTimeout(()=>{
    41. store.dispatch({
    42. type:'add'
    43. })
    44. },1000)
    45. })}>异步加一下</button>
    46. </div>
    47. )
    48. }
    49. }

    koa2 洋葱模型

    1. async function fn1(next) {
    2. console.log('fn1')
    3. await next();
    4. console.log('end fn1')
    5. }
    6. async function fn2(next) {
    7. console.log('fn2')
    8. await next();
    9. console.log('end fn2')
    10. }
    11. async function fn3(next) {
    12. console.log('fn3')
    13. await next();
    14. console.log('end fn3')
    15. }
    16. function compose2(middlewares){
    17. return function() {
    18. //执行第一个
    19. return dispatch(0)
    20. function dispatch(i) {
    21. let fn = middlewares[i]
    22. if(!fn){
    23. return Promise.resolve()
    24. }
    25. return Promise.resolve(
    26. fn(function next(){
    27. //执行下一个
    28. return dispatch(i+1)
    29. })
    30. )
    31. }
    32. }
    33. }
    34. const middlewares = [fn1,fn2,fn3];
    35. const finalFn = compose2(middlewares)
    36. finalFn()