当前位置:网站首页>浅聊缓存函数
浅聊缓存函数
2022-08-03 09:06:00 【InfoQ】
前文,我们已经聊过了:柯里化函数、偏函数,根据高阶函数的定义:
高阶函指使用其他函数作为参数、或者返回一个函数作为结果的函数。
柯里化函数、偏函数,都是妥妥的高阶函数!传入一个原函数,返回一个新函数。新函数继承了原函数的能力,又发展出不同的新能力!!
牛哇牛哇,初级前端开发,用函数封装过程,高级前端开发,用函数封装函数。
本篇再介绍一个新的高阶函数 ——
缓存函数
什么是缓存函数?什么情况下需要用到缓存函数?
本篇将用以下这个场景来解释:
比方说,我们这里有一个非常耗时的计算函数:
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
函数需要缓存,下次,可能是
balculate
或
dalculate
,难道还要去改这些函数的内部判断吗?
当然不!!缓存函数就是来解决这种困境的!!
代码如下:
/*
* 缓存函数 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 ,一直被存储着。并且返回的是回调函数,一样去接收后续的参数。
这样,既避免了多次创建全局变量,也避免了多次修改原函数内部。
用函数封装函数,高级!!
OK,以上便是本篇分享。点赞关注评论,为好文助力
我是掘金安东尼 100 万阅读量人气前端技术博主 INFP 写作人格坚持 1000 日更文 陪你一起度过漫长岁月
边栏推荐
- 别人都不知道的“好用”网站,让你的效率飞快
- Industry SaaS Microservice Stability Guarantee Actual Combat
- Path Prefixes (倍增!树上の二分)
- Redis cluster concept and construction
- IDEA2021.2安装与配置(持续更新)
- 【LeetCode】622. Design Circular Queue
- Gauva的ListenableFuture
- 多线程下的单例模式
- 深度学习之 10 卷积神经网络1
- Machine learning (formula derivation and code implementation)--sklearn machine learning library
猜你喜欢
随机推荐
判断根节点是否等于子节点之和
牛客 - 鼠标的天选(字符串哈希)
flutter 应用 抓包
自动化测试浏览器驱动下载版本对应关系
bihash总结
LeetCode 每日一题——622. 设计循环队列
开发工具之版本控制
验证浮点数输入
scala 并行集合、并行并发、线程安全问题、ThreadLocal
浅析什么是伪类和伪元素?伪类和伪元素的区别解析
IDEA2021.2安装与配置(持续更新)
文章列表的显示 以及创建文章 还有文章详情的基本
The display of the article list and the basics of creating articles and article details
深度学习之 10 卷积神经网络2
10 minutes to get you started chrome (Google) browser plug-in development
机器学习(公式推导与代码实现)--sklearn机器学习库
dflow部署简记
【LeetCode】112.路径总和
WPF 学习笔记《WPF样式基础》
unity的game界面里有canvas的线框?如何隐藏掉?