import { getChanceOfRain } from"magic-weather-calculator"; functionshowWeatherReport() { let result = getChanceOfRain(); // Let the magic happen console.log("The chance of rain tomorrow is:", result); }
showWeatherReport(); // (!) Triggers the calculation showWeatherReport(); // (!) Triggers the calculation showWeatherReport(); // (!) Triggers the calculation
import { getChanceOfRain } from"magic-weather-calculator"; let isCalculated = false; let lastResult; // We added this function! functionmemoizedGetChanceOfRain() { if (isCalculated) { // No need to calculate it again. return lastResult; } // Gotta calculate it for the first time. let result = getChanceOfRain(); // Remember it for the next time. lastResult = result; isCalculated = true; return result; } functionshowWeatherReport() { // Use the memoized function instead of the original function. let result = memoizedGetChanceOfRain(); console.log("The chance of rain tomorrow is:", result); }
showWeatherReport(); // (!) Triggers the calculation showWeatherReport(); // Uses the calculated result showWeatherReport(); // Uses the calculated result showWeatherReport(); // Uses the calculated result
然而对于有参数的场景就不适用了,因为缓存并没有考虑参数:
1 2 3 4 5 6 7
functionshowWeatherReport(city) { let result = getChanceOfRain(city); // Pass the city console.log("The chance of rain tomorrow is:", result); }
showWeatherReport("Tokyo"); // (!) Triggers the calculation showWeatherReport("London"); // Uses the calculated answer
import { getChanceOfRain } from"magic-weather-calculator"; let lastCity; let lastResult; functionmemoizedGetChanceOfRain(city) { if (city === lastCity) { // Notice this check! // Same parameters, so we can reuse the last result. return lastResult; } // Either we're called for the first time, // or we're called with different parameters. // We have to perform the calculation. let result = getChanceOfRain(city); // Remember both the parameters and the result. lastCity = city; lastResult = result; return result; } functionshowWeatherReport(city) { // Pass the parameters to the memoized function. let result = memoizedGetChanceOfRain(city); console.log("The chance of rain tomorrow is:", result); }
showWeatherReport("Tokyo"); // (!) Triggers the calculation showWeatherReport("Tokyo"); // Uses the calculated result showWeatherReport("Tokyo"); // Uses the calculated result showWeatherReport("London"); // (!) Triggers the calculation showWeatherReport("London"); // Uses the calculated result
在极端情况下等同于没有缓存:
1 2 3 4 5
showWeatherReport("Tokyo"); // (!) Triggers the calculation showWeatherReport("London"); // (!) Triggers the calculation showWeatherReport("Tokyo"); // (!) Triggers the calculation showWeatherReport("London"); // (!) Triggers the calculation showWeatherReport("Tokyo"); // (!) Triggers the calculation
// Remember the last result *for every city*. let resultsPerCity = newMap(); functionmemoizedGetChanceOfRain(city) { if (resultsPerCity.has(city)) { // We already have a result for this city. return resultsPerCity.get(city); } // We're called for the first time for this city. let result = getChanceOfRain(city); // Remember the result for this city. resultsPerCity.set(city, result); return result; } functionshowWeatherReport(city) { // Pass the parameters to the memoized function. let result = memoizedGetChanceOfRain(city); console.log("The chance of rain tomorrow is:", result); }
showWeatherReport("Tokyo"); // (!) Triggers the calculation showWeatherReport("London"); // (!) Triggers the calculation showWeatherReport("Tokyo"); // Uses the calculated result showWeatherReport("London"); // Uses the calculated result showWeatherReport("Tokyo"); // Uses the calculated result showWeatherReport("Paris"); // (!) Triggers the calculation
// Inside the magical npm package functiongetChanceOfRain() { // Show the input box! let city = prompt("Where do you live?"); // ... calculation ... } // Our code functionshowWeatherReport() { let result = getChanceOfRain(); console.log("The chance of rain tomorrow is:", result); }
// If this function only calculates things, // we would call it "pure". // It is safe to memoize this function. functiongetChanceOfRain(city) { // ... calculation ... } // This function is "impure" because // it shows a prompt to the user. functionshowWeatherReport() { // The prompt is now here let city = prompt("Where do you live?"); let result = getChanceOfRain(city); console.log("The chance of rain tomorrow is:", result); }
最后,我们可以将缓存函数抽象为高阶函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
functionmemoize(fn) { let isCalculated = false; let lastResult; returnfunctionmemoizedFn() { // Return the generated function! if (isCalculated) { return lastResult; } let result = fn(); lastResult = result; isCalculated = true; return result; }; }
这样生成新的缓存函数就方便啦:
1 2 3
let memoizedGetChanceOfRain = memoize(getChanceOfRain); let memoizedGetNextEarthquake = memoize(getNextEarthquake); let memoizedGetCosmicRaysProbability = memoize(getCosmicRaysProbability);