https://redux.js.org/glossary#middlewarejavascript
中間件在發送端 action端點 和 處理方reducer的端點之間。css
主要負責將async action轉換爲action, 或者記錄action日誌。html
A middleware is a higher-order function that composes a dispatch function to return a new dispatch function. It often turns async actions into actions.java
Middleware is composable using function composition. It is useful for logging actions, performing side effects like routing, or turning an asynchronous API call into a series of synchronous actions.redux
import { createStore, applyMiddleware } from 'redux' import todos from './reducers' function logger({ getState }) { return next => action => { console.log('will dispatch', action) // Call the next dispatch method in the middleware chain. const returnValue = next(action) console.log('state after dispatch', getState()) // This will likely be the action itself, unless // a middleware further in chain changed it. return returnValue } } const store = createStore(todos, ['Use Redux'], applyMiddleware(logger)) store.dispatch({ type: 'ADD_TODO', text: 'Understand the middleware' }) // (These lines will be logged by the middleware:) // will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' } // state after dispatch: [ 'Use Redux', 'Understand the middleware' ]
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.htmlapi
let next = store.dispatch; store.dispatch = function dispatchAndLog(action) { console.log('dispatching', action); next(action); console.log('next state', store.getState()); }
上面代碼中,對
store.dispatch
進行了重定義,在發送 Action 先後添加了打印功能。這就是中間件的雛形。數組中間件就是一個函數,對
store.dispatch
方法進行了改造,在發出 Action 和執行 Reducer 這兩步之間,添加了其餘功能。app
https://redux.js.org/api/applymiddlewareless
applyMiddleware(...middleware)
Middleware is the suggested way to extend Redux with custom functionality. Middleware lets you wrap the store's
dispatch
method for fun and profit. The key feature of middleware is that it is composable. Multiple middleware can be combined together, where each middleware requires no knowledge of what comes before or after it in the chain.async
Arguments
...middleware
(arguments): Functions that conform to the Redux middleware API. Each middleware receivesStore
'sdispatch
andgetState
functions as named arguments, and returns a function. That function will be given thenext
middleware's dispatch method, and is expected to return a function ofaction
callingnext(action)
with a potentially different argument, or at a different time, or maybe not calling it at all. The last middleware in the chain will receive the real store'sdispatch
method as thenext
parameter, thus ending the chain. So, the middleware signature is({ getState, dispatch }) => next => action
.
Returns
(Function) A store enhancer that applies the given middleware. The store enhancer signature is
createStore => createStore
but the easiest way to apply it is to pass it tocreateStore()
as the lastenhancer
argument.
應用中間件函數實現, 注意其中 對於middlewares數組, 使用compose函數進行組合, 其串聯方式是從 右 到 左, 即最右邊的被包裹爲最裏層,最早執行, 最左邊的被包裹到最外面, 最後執行。
https://www.cnblogs.com/liaozhenting/p/10166671.html
export default function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) } const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } const chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
以下圖很形象:
https://zhuanlan.zhihu.com/p/20597452
https://www.cnblogs.com/liaozhenting/p/10166671.html
/** * 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))) }
與pipe正好相反:
const pipe = (...fns) => { return (args) => { return fns.reduce((args, fn) => { return fn(args) }, args) } } const toUpper = (value) => { return value.toUpperCase(); } const addFont = (value) => { return 'hello plus!' + value; } console.log(pipe(addFont,toUpper)('test')); // HELLO PLUS!TEST
跟pip函數對比
console.log(pipe(addFont,toUpper)('test')); // HELLO PLUS!TEST console.log(compose(addFont,toUpper)('test')); // hello plus!TEST
http://www.bootcss.com/p/underscore/#compose
compose
_.compose(*functions)
返回函數集 functions 組合後的複合函數, 也就是一個函數執行完以後把返回的結果再做爲參數賦給下一個函數來執行. 以此類推. 在數學裏, 把函數 f(), g(), 和 h() 組合起來能夠獲得複合函數 f(g(h()))。var greet = function(name){ return "hi: " + name; }; var exclaim = function(statement){ return statement.toUpperCase() + "!"; }; var welcome = _.compose(greet, exclaim); welcome('moe'); => 'hi: MOE!'