前端小誌(轉型中)

一個用來記錄人老會忘記的地方

thunk是什麼

2018年01月13日
會知道thunk這個單字也是因為react-thunk,一開始也是傻傻的用,後來才常常在functional的文章看到這個詞,整理整理希望能對functional programming更了解。

根據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再提囉。


展開Disqus
分類
最近文章
友站連結
© 2019 Ernie Yang