cached

栏目: source 发布时间:2025-10-14
/**
 * Create a cached version of a pure function.
 */
function cached<R>(fn: (str: string) => R): (sr: string) => R {
  const cache: Record<string, R> = Object.create(null)
  return function cachedFn(str: string) {
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }
}

这段代码实现了一个函数结果缓存装饰器,用于优化纯函数(Pure Function)的执行效率。以下是逐层解读:

1. 核心功能

  • 输入:一个接收字符串参数、返回任意类型R的纯函数fn
  • 输出:一个带缓存功能的新函数cachedFn
  • 行为:当新函数被调用时,若传入参数str已在缓存中,直接返回缓存结果;否则调用原函数fn(str)并将结果存入缓存后返回

2. 代码逐行解析

export function cached<R>(fn: (str: string) => R): (sr: string) => R {
  // 创建无原型的空缓存对象(避免原型链污染)
  const cache: Record<string, R> = Object.create(null)
  
  return function cachedFn(str: string) {
    // 检查缓存是否已存在
    const hit = cache[str]
    
    // 短路操作:存在缓存则直接返回,否则计算并存储
    return hit || (cache[str] = fn(str))
  }
}

3. 关键设计解析

  • 缓存对象设计
    使用Object.create(null)创建无原型对象,避免toString/hasOwnProperty等原型方法与缓存键冲突,确保cache[str]严格匹配用户传入的字符串。

  • 短路求值逻辑
    hit || (cache[str] = fn(str))利用了JavaScript的逻辑或特性:

    • cache[str]存在(非falsy),直接返回缓存值
    • 若不存在,执行cache[str] = fn(str)表达式(该表达式返回赋值结果),实现"计算→存储→返回"三合一操作
  • 纯函数前提
    该缓存策略严格依赖函数纯度:只有当fn是纯函数(相同输入恒定输出)时,缓存结果才安全有效。若传入非纯函数,可能导致返回陈旧数据。

4. 典型使用场景

// 原始函数:计算字符串长度(纯函数示例)
const getLength = (str: string) => str.length

// 创建缓存版本
const cachedLength = cached(getLength)

// 首次调用:计算并缓存
cachedLength('hello') // 5(执行getLength)

// 二次调用:命中缓存
cachedLength('hello') // 5(直接返回缓存)

5. 性能优化原理

通过空间换时间策略,避免相同参数的重复计算。在字符串操作频繁的场景(如模板编译、文本处理)中,可显著提升性能。

6. 注意事项

  • 缓存失效问题:当函数逻辑更新时,旧缓存不会自动清除,需手动重置缓存对象
  • 内存占用:长期运行的程序中,缓存可能持续增长,需根据业务场景设置淘汰策略
  • 非纯函数风险:若装饰非纯函数,会导致返回结果与预期不符

这种模式在Vue源码、Lodash的_.memoize等场景中被广泛采用,是函数式编程中常见的性能优化手段。

本文地址:https://www.tides.cn/p_vue-source-cached