https://github.com/reduxjs/redux-thunkjavascript
Why Do I Need This?
Thunks are the recommended middleware for basic Redux side effects logic, including complex synchronous logic that needs access to the store, and simple async logic like AJAX requests.html
Motivation
Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods
dispatch
andgetState
as parameters.java
相對於同步action, 修改state場景, 對於異步場景, 或者 複雜的同步場景, 就須要thunk中間件。 react
thunk中間件容許actionCreator返回的dispatch的對象, 再也不試普通對象的action(包括type 和 payload參數), git
而是一個函數,函數入參爲 dispatch 和 getState , 在此函數中處理異步調用 或者 複雜條件的 處理。github
異步請求的例子:express
const INCREMENT_COUNTER = 'INCREMENT_COUNTER'; function increment() { return { type: INCREMENT_COUNTER }; } function incrementAsync() { return dispatch => { setTimeout(() => { // Yay! Can invoke sync or async actions with `dispatch` dispatch(increment()); }, 1000); }; }
條件dispatch例子:redux
function incrementIfOdd() { return (dispatch, getState) => { const { counter } = getState(); if (counter % 2 === 0) { return; } dispatch(increment()); }; }
給store添加thunk中間件promise
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers/index'; // Note: this API requires redux@>=3.1.0 const store = createStore( rootReducer, applyMiddleware(thunk) );
dispatch a thunk action:緩存
function fetchSecretSauce() { return fetch('https://www.google.com/search?q=secret+sauce'); } function makeASandwichWithSecretSauce(forPerson) { // Invert control! // Return a function that accepts `dispatch` so we can dispatch later. // Thunk middleware knows how to turn thunk async actions into actions. return function (dispatch) { return fetchSecretSauce().then( sauce => dispatch(makeASandwich(forPerson, sauce)), error => dispatch(apologize('The Sandwich Shop', forPerson, error)) ); }; } // Thunk middleware lets me dispatch thunk async actions // as if they were actions! store.dispatch( makeASandwichWithSecretSauce('Me') );
dispatch返回結果其實是一個promise,可使用 then語句觀察結果:
// It even takes care to return the thunk’s return value // from the dispatch, so I can chain Promises as long as I return them. store.dispatch( makeASandwichWithSecretSauce('My partner') ).then(() => { console.log('Done!'); });
https://github.com/reduxjs/redux-thunk
thunk就是一個函數包裹了一個表達式, 表達式延遲執行。
What’s a thunk?!
A thunk is a function that wraps an expression to delay its evaluation.
// calculation of 1 + 2 is immediate // x === 3 let x = 1 + 2; // calculation of 1 + 2 is delayed // foo can be called later to perform the calculation // foo is a thunk! let foo = () => 1 + 2;
The term originated as a humorous past-tense version of "think".
https://en.wikipedia.org/wiki/Thunk#cite_note-1
一段程序,不馬上執行, 而是在真正使用的地方, 才計算其值。
相關術語:
call by name
lazy evaluation
表現形式爲, 使用匿名函數封裝, 等待調用執行任務。
In computer programming, a thunk is a subroutine used to inject an additional calculation into another subroutine. Thunks are primarily used to delay a calculation until its result is needed, or to insert operations at the beginning or end of the other subroutine. It can simply be thought of as a function that takes no arguments, waiting to be called upon to do its work. They have a variety of other applications in compiler code generation and modular programming.
以下面的例子: hypot(3, 4)語句計算比較耗時,將其封裝爲匿名函數, 在使用的地方調用匿名函數,就至關於執行hypot(3, 4)。
// 'hypot' is a function that returns another function which is already closed over all required data const hypot = (x, y) => () => Math.sqrt(x * x + y * y); // 'thunk' is a function that takes no arguments and performs a potentially expensive operation (computing a square root, in this example) and/or causes some side-effect to occur const thunk = () => hypot(3, 4); // the thunk can then be passed around... doSomethingWithThunk(thunk); // ...or evaluated thunk(); // === 5
以下wiki描述, thunk爲最先使用在ada語言的執行上, 當其執行時候, 對於函數參數的類型, 其實能夠在編譯的時候經過一些思考(thought)肯定, 這個肯定的過程, 被稱爲thunk。
增長編譯時候的一點點小時間, 從而提升解釋時候的效率, 減小時間, 這個類型推斷的過程, 若是在執行階段執行, 那麼會被屢次執行; 若是每次執行都是同樣結果, 那麼徹底沒有必要屢次執行,
在編譯時候肯定(thought), 或者在過程的第一次執行後肯定(thought),進而被緩存起來,能夠被屢次使用。
這種過程的形式被固化下來,並被推廣到其它應用場景, 並被命名爲thunk。
Eric Raymond rejects "a couple of onomatopoeic myths circulating about the origin of this term" and cites the inventors of the thunk recalling that the term "was coined after they realized (in the wee hours after hours of discussion) that the type of an argument in Algol-60 could be figured out in advance with a little compile-time thought [...] In other words, it had 'already been thought of'; thus it was christened a thunk, which is 'the past tense of "think" at two in the morning'. See: Raymond, Eric S. (1996). Raymond, Eric S., ed. The New Hacker's Dictionary. MIT Press. p. 445. ISBN 9780262680929. Retrieved 2015-05-25.
http://www.ruanyifeng.com/blog/2015/05/thunk.html
編譯器的"傳名調用"實現,每每是將參數放到一個臨時函數之中,再將這個臨時函數傳入函數體。這個臨時函數就叫作 Thunk 函數。
function f(m){ return m * 2; } f(x + 5); // 等同於 var thunk = function () { return x + 5; }; function f(thunk){ return thunk() * 2; }
上面代碼中,函數 f 的參數 x + 5 被一個函數替換了。凡是用到原參數的地方,對 Thunk 函數求值便可。
這就是 Thunk 函數的定義,它是"傳名調用"的一種實現策略,用來替換某個表達式。
以下圖,阮老師的文章描述, redux框架,將應用分爲 action reducer view三個部分,
對於異步獲取數據, 或者添加條件過濾數據場景, 這個過程,在view(react.componet)中實現是不合適, 由於其只負責視圖展現,
放在reducer中不行了, 由於框架規定reducer只能做爲純函數使用,
這個重任只能交給 action, 實現 thunk action來作中間層邏輯,此邏輯對數據獲取和數據更新到狀態負責, 術語 redux store的數據管理和維護的範圍。
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
Action 發出之後,過一段時間再執行 Reducer,這就是異步。
怎麼才能 Reducer 在異步操做結束後自動執行呢?這就要用到新的工具:中間件(middleware)。