什么是缓存函数
所谓缓存函数就是将函数运算过的结果缓存起来,这种做法是典型的用内存去换取性能的手段,常用于缓存数据计算结果和缓存对象。缓存只是一个临时的数据存储,它保存数据,以便将来对该数据的请求能够更快地得到处理。
记忆函数的使用场景
在客户前端页面中,有些数据(比如一些后续不常改变的数据),可以在第一次请求的时候全部拿过来保存在 js 对象中,以后需要的时候就不用每次都去请求服务器了。对于那些大量使用类似下拉框的页面,这种方法可以极大地减少对服务器的访问。可以提供便利,减少查询次数和所消耗的时间。
函数缓存的实现原理
- 闭包(相关介绍可以查阅这篇文章)
- 高阶函数
高阶函数
JavaScript 的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
我们可以利用高阶函数的思想来实现一个简单的缓存,在函数内部用一个对象存储输入的参数,如果下次再输入相同的参数,那就比较一下对象的属性,把值从这个对象里面取出来,不必再继续往运行,这样就极大的节省了客户端等待的时间。
function serialize(obj) {
if(obj == null) {
return ''
} else if(Array.isArray(obj)) {
const items = obj.map((item) => serialize(item) )
return `[${items.join(',')}]`
} else if(isPlainObject(obj)) {
const keys = Object.keys(obj)
keys.sort()
const items = keys.map((key) => `${key}=${serialize(obj[key])}`)
return `{${items.join('&')}}`
} else if(typeof obj === 'object' && typeof obj.valueOf === 'function') {
return serialize(obj.valueOf())
} else {
return obj + ''
}
}
function isPlainObject(obj) {
let prototype = Object.getPrototypeOf(obj)
return obj && typeof obj === 'object' && (prototype === null || prototype === Object.prototype)
}
function memorize(fn) {
const results = {}
return (...args) => {
const key = serialize(args)
if(!(key in results)) {
console.log('新的缓存')
results[key] = fn.apply(this, args)
}
console.log('缓存结果', results)
return results[key]
}
}
const add = (...args) => {
return args.reduce((accValue, curValue, index) => accValue + curValue, 0)
}
const adder = memorize(add)
adder(1, 2, 3) // 新的缓存, 缓存结果 {[1,2,3]: 6}
adder(1, 2, 3) // 缓存结果 {[1,2,3]: 6}
adder(1, 2, 3, 4, 5) // 新的缓存, 缓存结果 {[1,2,3]: 6, [1,2,3,4,5]: 15}
我们在 memorize 里入参一个函数并返回了一个闭包函数,根据序列化比较这个函数参数是否有变动,判断是从闭包作用域上 results 取值还是重新执行入参函数。可以看到只要参数相同,每次取值都会在闭包作用域上缓存的 results 里取。