「30s代码解析挑战」可缓存的函数

124 阅读2分钟

这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战 | 创作学习持续成长,夺宝闯关赢大奖

解析30 seconds of code网站代码片段之「可缓存的函数」

可缓存的函数

const memoize = (fn) => {
  const cache = new Map();
  const cached = function (val) {
    return cache.has(val)
      ? cache.get(val)
      : cache.set(val, fn.call(this, val)) && cache.get(val);
  };
  cached.cache = cache;
  return cached;
};

// 举例
const cachedFunc = memoize(testFun);
testFun(param); // 运行即缓存
testFun(param); //第二次的结果会快于第一次

流程解析

  • 通过新建空的map来缓存函数结果,通过属性的形式挂载在返回出去的cached函数上来保证后续cache能被获取。
  • memorize函数返回一个可缓存的cached函数,然后通过传参时map判断是否缓存来返回最终结果。如果已缓存就直接返回缓存结果,如果未缓存就运行函数并且缓存结果。

技术解析

memoization主要是使用缓存来存储结果,以便后续调用耗时的函数不会再次执行一遍函数,这样来加快代码速度。

  • Memoization 应该主要用于加速性能缓慢、成本高或耗时的函数调用
  • Memoization 可加快后续调用的速度,因此最好预计在相同情况下对同一函数进行多次调用时使用
  • Memoization 将结果存储在内存中,因此在非常不同的情况下多次调用同一函数时就最好别缓存,不然会给内存造成负担

vue中的computed就是通过map缓存来实现的。

thinking

memoize函数的实现其实比较简单,利用ES6的新特性map方法很轻松就实现了,所以这里的思考主要是想说这个函数不能随便乱用。缓存数据加快函数的运算速度听起来挺好,但是对于需要频繁计算/函数入参频繁变化的函数,会使得map在内存中的体积快速加大,内存负担就会导致运算速度下降。

目前,我自己遇到一个使用场景:用户在编辑器类编辑的文章,需要分析文章的DOM结构得到结构化参数,这个分析行为可以抽象为一个函数。分析一次DOM结构是比较耗时的,我翻了翻项目里至少有三个场景需要用到这个函数的结果,原来的写法就是相同的入参(文章的DOM结构是不变的)这个函数在不同地方调用了三次,未来可能更多。此时,就需要缓存函数将第一次分析的结果缓存了,之后再调用就可以直接使用缓存的结果。

所以我使用这个对项目代码进行了一个小改造,也算是一个小的性能提升。