JavaScript中的记忆化介绍

69 阅读2分钟

JavaScript中的记忆化介绍

记忆化是一种技术,它可以让你大大加快你的应用程序的速度。

它不是JavaScript特有的技术,尽管我把这篇文章标记为 "JavaScript",因为我将提供一些JS的例子。

Memoization是指在我们运行一个函数后,将该函数的调用结果存储在该函数本身。当我们下次调用该函数时,它不会再执行一次 "常规 "的执行,而是将存储的结果返回给我们。

这就是函数的缓存

为什么这很有用呢?

假设我们的函数需要1秒钟的时间来运行,而缓存让我们把这个过程加快到2毫秒。这里有一个明显的收益。

听起来很不错。问题出在哪里呢?

如果用同一组参数调用一个函数的结果是相同的输出,那么记忆化就会起作用。换句话说,这个函数必须是纯粹的。否则缓存结果就没有意义了。

所以,数据库查询、网络请求、写到文件和其他非纯操作不能用记忆化来优化。对于这些,你需要找到其他方法来优化它们。或者只是忍受它们的低效率,这有时是不可避免的。

让我们来创造一个例子。

// Calculate the factorial of 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() ,但这次很有用)。

请看Flavio Copes (@flaviocopes)在CodePen上做的PenMemoization例子factorial

有一些库可以将记忆化功能添加到任何纯函数中,所以你可以跳过修改函数本身的任务,但你只是用这个功能来装饰它。

我特别提到了fast-memoize

Lodash也有一个memoize() 方法,如果你是Lodash的粉丝。