js如何实现函数缓存?函数缓存有什么运用场景?

在 JavaScript 中,您可以通过多种方式实现函数缓存,主要利用闭包或 Map 对象。以下列举两种常见方法以及它们的应用场景:

1. 使用闭包实现函数缓存:

function memoize(fn) {
  const cache = {};
  return function(...args) {
    const key = JSON.stringify(args); // 将参数数组转换为字符串作为键
    if (cache[key]) {
      console.log(`Cache hit for ${key}`);
      return cache[key];
    } else {
      console.log(`Calculating result for ${key}`);
      const result = fn(...args);
      cache[key] = result;
      return result;
    }
  };
}


// 示例用法:
function expensiveCalculation(a, b) {
  // Simulate a computationally expensive operation
  let result = 0;
  for (let i = 0; i < 100000000; i++) {
    result += a * b;
  }
  return result;
}

const memoizedCalculation = memoize(expensiveCalculation);

console.time('First call');
console.log(memoizedCalculation(2, 3)); // 计算并缓存结果
console.timeEnd('First call');

console.time('Second call');
console.log(memoizedCalculation(2, 3)); // 从缓存中获取结果
console.timeEnd('Second call');

console.time('Third call with different arguments');
console.log(memoizedCalculation(3, 4)); // 计算并缓存新结果
console.timeEnd('Third call with different arguments');

console.time('Fourth call with same arguments as third');
console.log(memoizedCalculation(3, 4)); // 从缓存中获取结果
console.timeEnd('Fourth call with same arguments as third');

2. 使用 Map 对象实现函数缓存:

function memoize(fn) {
  const cache = new Map();
  return function(...args) {
    const key = JSON.stringify(args); //  将参数数组转换为字符串作为键.  对于非字符串参数,使用更稳健的 key 生成方法,例如使用 Map 的复合键功能或自定义的哈希函数。
    if (cache.has(key)) {
      console.log(`Cache hit for ${key}`);
      return cache.get(key);
    } else {
      console.log(`Calculating result for ${key}`);
      const result = fn(...args);
      cache.set(key, result);
      return result;
    }
  };
}

//  示例用法同上

使用 Map 的好处:

  • 处理各种数据类型的键:Map 可以使用任何数据类型作为键,而不仅仅是字符串。这在处理对象或函数作为参数时非常有用。
  • 更好的性能: 对于大量缓存数据,Map 通常比对象提供更好的性能,尤其是在查找和插入方面。
  • 迭代能力:Map 提供了内置的迭代方法,可以更方便地遍历缓存数据。

函数缓存的应用场景:

  • 减少重复计算: 对于计算成本高的函数,缓存可以避免重复计算,显著提高性能。例如,递归函数、复杂的数学运算、网络请求等。
  • 优化渲染性能: 在前端开发中,可以使用缓存来存储组件的渲染结果,避免重复渲染,提高页面加载速度和响应速度。 React 中的 useMemoReact.memo 就是利用了这个原理.
  • 记忆化搜索: 在算法设计中,记忆化搜索是一种常用的优化技术,它将已经计算过的结果缓存起来,避免重复搜索,提高算法效率。例如,动态规划问题。
  • API 调用限制: 如果对 API 的调用次数有限制,可以使用缓存来存储 API 的响应结果,减少 API 调用次数。

选择哪种方法?

两种方法都能实现函数缓存,但 Map 方法通常更具优势,因为它能处理更复杂的数据类型作为键,并且性能更好。 除非你的项目对兼容性有非常严格的要求(需要支持非常老的浏览器),否则推荐使用 Map 方法。

更健壮的键生成:

在实际应用中,JSON.stringify 可能不足以处理所有情况,特别是对于包含循环引用或复杂对象的参数。 考虑使用更健壮的键生成方法,例如:

  • 针对特定数据类型进行序列化: 如果参数类型已知,可以编写自定义的序列化函数。
  • **使用哈希
posted @ 2024-12-12 06:04  王铁柱6  阅读(59)  评论(0编辑  收藏  举报