根據wiki的定義
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 it is needed, or to insert operations at the beginning or end of the other subroutine. They have a variety of other applications to compiler code generation and in modular programming.
我的翻譯是thunk是其他程序要計算之前的另一個處理程序,不過聽起來很繞口,也不知道實際用途。
這就要探討電腦世界中的求值策略(Evaluation strategy)了-定義何時和以何種次序求值給函式的實際參數,什麼時候把它們代換入函式,和代換以何種形式發生。
假設我們在javascript中,做以下的事情
const x = 1;
const add = num => num + 1;
add(x + 2);
那function的參數到底是什麼時候被計算?
if 傳值呼叫(call by value)
const x = 1;
const add = num => num + 1;
add(x + 2);
// ==> add(3)
if 傳名呼叫 (Call by name)
const x = 1;
const add = num => num + 1;
add(x + 2);
// ==> (x + 2) + 1
如果今天的參數不是一個簡單的(x + 2),而是一個複雜的計算,且function裡面沒有用到(可能沒有走進if else condition),那其實先將值求好是沒有義意的,所以傳名呼叫更傾向於原封不動的將參數先放入,等有需要的時候再使用。
不過javascript的實作是傳值呼叫,所以我們會依靠thunk來幫我們處理此問題。
所以thunk有一個很重要的特性就是lazy evaluation,表達式不在它被綁定到變量之後就立即求值,而是在該值被取用的時候求值。
所以redux-thunk表達的是delay(lazy) dispatch的直接使用。
在javscript裡面寫成high order function就是thunk的應用(待求証)。假設我有一個判斷session的api,可能在很多地方使用,可以寫成以下。
const checkSession = () => fetch('MY_API/session');
// any place
const isLoggin = checkSession();
你不用直接的把值求出來,而是用到的時候再呼叫。
如果是每次都一定會用到的值或是沒必要delay就不要用thunk了,因為thunk多跑了一層function反而會降低效率。
const action1 = ({
type: TEST,
});
//多跑一層
const action2 = () => dispatch => (
dispatch({
type: TEST,
})
)
正規的lazy evaluation是call by need,這是進階的call by name
Call by need is a memoized version of call by name.
在functional的世界中,給定一個function,每次給相同的input必定得到相同的output,我們可以稱這為pure function。
f(x) = g(x) + 1
若是g(x)為很heavy或是expensive的function,那我們可以做memized將算完的結果儲存。
cache = {}
cache[v] = y
另外一個lazy evaluation的特性是最小化求值,這下次講functional的performance issue再提囉。