記憶化是另一個令人生畏的術語,當你理解它時,它就會變得非常直觀。今天我們就來了解什麼是記憶吧!
記憶化是許多程式語言中使用的最佳化技術,用於減少冗餘、昂貴的函數呼叫的數量。這是透過根據函數的輸入快取函數的返回值來完成的。在這篇文章中,我們將建立一個次優但希望具有教育意義的 JavaScript 函數記憶體!
這是一個供我們記憶的函數。它以非常低效的方式求出數字的平方。
const inefficientSquare = num => {
let total = 0;
for (let i = 0; i < num; i++) {
for (let j = 0; j < num; j++) {
total++;
}
}
return total;
};
我們可以使用相同的值來執行這個函數,並且每次都需要一段時間來執行。
const start = new Date();
inefficientSquare(40000);
console.log(new Date() - start);
// 1278
const start2 = new Date();
inefficientSquare(40000);
console.log(new Date() - start2);
// 1245
每次都超過一秒,哎呀!
在編寫任何程式碼之前,讓我們先透過記憶體進行推理。
將對函數的引用作為輸入
傳回一個函數(因此可以像平常一樣使用)
建立某種緩存來保存先前函數呼叫的結果
以後任何時候呼叫該函數,都會傳回快取結果(如果存在)
如果快取的值不存在,則呼叫該函數並將結果儲存在快取中
這是上述偽程式碼大綱的實作。正如簡介中提到的,這是次優的,您不應該在生產中使用它。後面我會解釋為什麼!
// Takes a reference to a function
const memoize = func => {
// Creates a cache of results
const results = {};
// Returns a function
return (...args) => {
// Create a key for results cache
const argsKey = JSON.stringify(args);
// Only execute func if no cached value
if (!results[argsKey]) {
// Store function call result in cache
results[argsKey] = func(...args);
}
// Return cached value
return results[argsKey];
};
};
此實作中最次優的部分,以及為什麼我不建議在生產程式碼中使用它,是使用JSON.stringify
在results
快取中建立鍵。 JSON.stringify
的最大問題是它不會序列化某些輸入,例如函數和符號(以及您在 JSON 中找不到的任何內容)。
讓我們複製inefficientSquare
範例,但這次我們將使用 memoizer 來快取結果。
const memoize = func => {
const results = {};
return (...args) => {
const argsKey = JSON.stringify(args);
if (!results[argsKey]) {
results[argsKey] = func(...args);
}
return results[argsKey];
};
};
const inefficientSquare = memoize(num => {
let total = 0;
for (let i = 0; i < num; i++) {
for (let j = 0; j < num; j++) {
total++;
}
}
return total;
});
const start = new Date();
inefficientSquare(40000);
console.log(new Date() - start);
// 1251
const start2 = new Date();
inefficientSquare(40000);
console.log(new Date() - start2);
// 0
成功!第二次我們使用相同的輸入呼叫inefficientSquare
時,不需要時間重新計算;我們只是從物件中提取快取的值。
記憶化很棒,但只有當你的函數是純函數時才有效。換句話說,如果函數的回傳值不僅僅依賴其輸入,那麼這些輸入的快取值將不會總是正確的。此外,如果您的函數有副作用,記憶體不會複製這些副作用,它只會傳回最終返回的函數值。
現在您應該很清楚我們如何以及為什麼使用記憶化!雖然我們的記憶功能不是最佳的,但您可以使用許多第三方函式庫,它們會做得更好。只要確保您記住的函數是純函數即可!
原文出處:https://dev.to/nas5w/an-introduction-to-memoization-59o