浅聊缓存函数

简介: 浅聊缓存函数

image.png

前文,我们已经聊过了:柯里化函数、偏函数,根据高阶函数的定义:


高阶函指使用其他函数作为参数、或者返回一个函数作为结果的函数。


柯里化函数、偏函数,都是妥妥的高阶函数!传入一个原函数,返回一个新函数。新函数继承了原函数的能力,又发展出不同的新能力!!

牛哇牛哇,初级前端开发,用函数封装过程,高级前端开发,用函数封装函数。

本篇再介绍一个新的高阶函数 —— 缓存函数


image.png


什么是缓存函数?什么情况下需要用到缓存函数?

本篇将用以下这个场景来解释:


比方说,我们这里有一个非常耗时的计算函数:


const calculate = (num)=>{
    const startTime = new Date()
    for(let i=0;i<num;i++){} // 大数计算
    const endTime = new Date()
    return endTime - startTime
}
console.log(calculate(10_000_000_000))
// 10465


遍历数字 100 亿,需耗时 10s +,打印出这个值;

问:有什么办法能够缓存下来这个值,等到下次再次调用 calculate(10_000_000_000) 的时候,不需要再次进行计算,直接就输出这个计算结果??


有人说:着还不简单吗,直接把结果付给一个变量,let result = calculate(10_000_000_000) ,下次直接拿 result的值不就行了吗?


从实现上讲,当然是可以的;不过,从设计模式的角度来讲,就不太ok了!


为什么?


因为声明 result 变量作为一个全局变量要一直存在,不管未来你用或者不用,它都存在着,占用着内存;


设想下,如果有 N 个大数的计算,要写 N 个变量去存吗?即使有一些是后面不会再重复被调用了的。


let result = calculate(10_000_000_000)
let result1 = calculate(10_000_000_0000)
......
let resultN = calculate(10_000_000_0000...000)


又有朋友说了:“我有好主意”!


我直接声明一个缓存对象,再改写 calculate 函数内部,计算的时候判断一下,算过了的,就从对象里面拿,没算过的,才会进行计算。


代码如下:

let cacheObj = {}
const calculate = (num)=>{
        if(!cacheObj[num]){
            const startTime = new Date()
            for(let i=0;i<num;i++){}
            const endTime = new Date()
            cacheObj[num] = endTime - startTime
        }
    return cacheObj[num]
}


本瓜不得不说:你这孩子打小就聪明!


但是,忘记开闭原则了吗?我们尽量要少修改原函数,而是尽量在其基础上去拓展它。


这次是 calculate 函数需要缓存,下次,可能是 balculatedalculate ,难道还要去改这些函数的内部判断吗?

当然不!!缓存函数就是来解决这种困境的!!


代码如下:

/*
* 缓存函数 cashed
*/
function cached(fn){ // 传入需要缓存结果的函数
  const cacheObj = Object.create(null); // 创建一个对象
  return function cachedFn (str) { // 返回回调函数
    if ( !cacheObj [str] ) { // 在对象里面查询,函数结果是否被计算过
        let result = fn(str);
        cacheObj [str] = result; // 没有则要执行原函数,并把计算结果缓存起来
    }
    return cacheObj [str] // 被缓存过,直接返回
  }
}
// calculate 计算大数的函数(也可以叫原函数)
const calculate = (num)=>{
    const startTime = new Date()
    for(let i=0;i<num;i++){}
  const endTime = new Date()
    return endTime - startTime
}
// 经过缓存函数 cashed 将原函数 calculate 封装,让原函数具有缓存的新功能
let cashedCalculate = cached(calculate)
cashedCalculate(10_000_000_000) // 10465


计算结果,就已经被缓存到 cashedCalculate 里面了,我们再次调用:

cashedCalculate(10_000_000_000) // 10465


会立即得到计算结果 !


小结:

哈哈,就是这样巧妙的思路,如果问缓存函数的究极奥义是啥?

本瓜会答:是闭包!闭包太强了,用 cached 函数处理 calculate 的时候,就留下了一个闭包对象 cacheObj ,一直被存储着。并且返回的是回调函数,一样去接收后续的参数。


这样,既避免了多次创建全局变量,也避免了多次修改原函数内部。

用函数封装函数,高级!!


相关文章
|
1天前
|
存储 缓存 NoSQL
除了`functools.lru_cache`装饰器,还有哪些方法可以缓存函数的结果?
除了`functools.lru_cache`装饰器,还有哪些方法可以缓存函数的结果?
20 1
|
1天前
|
缓存 Python
如何使用`functools`模块中的`lru_cache`来进行函数结果缓存?
如何使用`functools`模块中的`lru_cache`来进行函数结果缓存?
58 0
|
1天前
|
缓存 前端开发 JavaScript
JavaScript如何实现函数缓存?函数缓存有哪些应用场景?
在JavaScript中,可以通过函数缓存来提高函数的执行效率。函数缓存指的是将函数的计算结果缓存起来,当下次使用相同的参数调用该函数时,直接返回缓存中的结果,避免重复计算。
31 0
|
存储 缓存 索引
图解 Google V8 # 16:V8是怎么通过内联缓存来提升函数执行效率的?
图解 Google V8 # 16:V8是怎么通过内联缓存来提升函数执行效率的?
133 0
图解 Google V8 # 16:V8是怎么通过内联缓存来提升函数执行效率的?
|
缓存 前端开发 大数据
如何设计一个缓存函数
在项目中你有优化过自己写过的代码吗?或者在你的项目中,你有用过哪些技巧优化你的代码,比如常用的函数防抖、节流,或者异步懒加载、惰性加载等。
102 0
如何设计一个缓存函数
|
缓存
lodash函数缓存化
lodash函数缓存化
198 0
|
缓存 前端开发 程序员
缓存函数的简单使用
缓存是一种重要的程序优化手段,一般采用以空间换时间的措施来提高程序性能,常用的缓存方法有浏览器缓存、HTTP 缓存等。
161 0
缓存函数的简单使用
|
缓存 监控 Android开发
【Android 逆向】函数拦截实例 ( ③ 刷新 CPU 高速缓存 | ④ 处理拦截函数 | ⑤ 返回特定结果 )
【Android 逆向】函数拦截实例 ( ③ 刷新 CPU 高速缓存 | ④ 处理拦截函数 | ⑤ 返回特定结果 )
113 0
|
存储 缓存 Java
【Android 逆向】函数拦截 ( 使用 cache_flush 系统函数刷新 CPU 高速缓存 | 刷新 CPU 高速缓存弊端 | 函数拦截推荐时机 )
【Android 逆向】函数拦截 ( 使用 cache_flush 系统函数刷新 CPU 高速缓存 | 刷新 CPU 高速缓存弊端 | 函数拦截推荐时机 )
126 0
【Android 逆向】函数拦截 ( 使用 cache_flush 系统函数刷新 CPU 高速缓存 | 刷新 CPU 高速缓存弊端 | 函数拦截推荐时机 )
|
Android开发
【Android 逆向】函数拦截 ( CPU 高速缓存机制 | CPU 高速缓存机制 导致 函数拦截失败 )
【Android 逆向】函数拦截 ( CPU 高速缓存机制 | CPU 高速缓存机制 导致 函数拦截失败 )
90 0
【Android 逆向】函数拦截 ( CPU 高速缓存机制 | CPU 高速缓存机制 导致 函数拦截失败 )