介紹JavaScript中Memoization的技巧

Memoization是一種讓你的應用程式大大加速的技巧。

儘管我將這篇文章標記為“JavaScript”,但Memoization並不是JavaScript獨有的技術,我會提供一些JavaScript的例子。

Memoization是在我們運行函數後,將函數調用的結果存儲在該函數本身中的動作。下次調用該函數時,它不會再次執行“常規”運算,而是直接返回存儲的結果。

這其實是對函數進行緩存。

為什麼這很有用?

假設我們的函數需要1秒的執行時間,而Memoization可以將這個過程加速到2毫秒。這裏明顯有個好處。

聽起來很酷。有什麼限制嗎?

Memoization僅在調用帶有相同參數集的函數時,結果相同的情況下才有效。換句話說,函數必須是純函數。否則,對結果進行緩存就沒有意義。

因此,無法優化使用Memoization的操作包括數據庫查詢、網絡請求、文件讀寫等非純函數操作。對於這些情況,您將需要找到其他方法來進行優化。或者接受它們的低效率,有時是不可避免的。

讓我們創建一個例子:

// 計算num的階乘
const fact = num => {
 if (!fact.cache) {
 fact.cache = {}
 }
 if (fact.cache[num] !== undefined) {
 console.log(num + ' cached')
 return fact.cache[num];
 } else {
 console.log(num + ' not cached')
 }
 fact.cache[num] = num === 0 ? 1 : num * fact(num - 1)
 return fact.cache[num]
}

這個例子計算一個數字的階乘。當第一次運行fact()時,它在函數本身上創建一個cache物件屬性,用於存儲計算的結果。

每次調用時,如果在cache物件中找不到數字的結果,我們進行計算。否則,我們只返回那個結果。

試著運行它。我製作了一個Codepen來方便測試,它使用document.write()來輸出到HTML頁面(這是我很久以前用document.write(),但這次它很有用)。

請參考Memoization Example Factorial的Codepen鏈接查看運行結果。

有一些庫可以為任何純函數添加Memoization功能,這樣您就可以跳過修改函數本身的任務,只需使用這個功能將其裝飾起來。

特別要提到的是fast-memoize

如果您是Lodash的粉絲,Lodash還有一個memoize()方法