vue2中的缓存函数
vue2版本中有这么一个缓存函数
/**
* Create a cached version of a pure function.
*/
function cached (fn) {
var cache = Object.create(null);
return (function cachedFn (str) {
var hit = cache[str];
return hit || (cache[str] = fn(str))
})
}
上面这个函数存在一个常用场景,比如存在一个数组,需要把每个元素的首字母转为大写。
const array = ['abc', 'ed', 'abc', 'acd', 'ed', 'fkg', ...];
常用的解决方法
// 定一个capitalize函数
function capitalize (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
};
const capitalizeArray = array.map(capitalize);
细心的我们会发现array中存在不少重复的元素, 他们返回的结果一样的,实际不需要重复计算执行capitalize,而且capitalize是一个PURE函数,此时我们可以利用上面的cached做一个备忘录的功能。
改造如下
function capitalize (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
};
const capitalizeArray = array.map(cached(capitalize));
当遇到重复字符串的时候会直接返回缓存的结果。想想capitalize是一个十分耗时的任务,性能优化不止一点点。
改造vue缓存函数
上面的举例是缓存同步任务的纯函数,在业务开发中存在这么一个场景,输入框搜索。当输入框触发input事件的时候,我们都会调用接口返回查询结果。比如我输入了掘金关键字返回了结果,然后又输入掘金NBA返回了结果,此时我删掉了NBA,又查询掘金, 实际上这个结果我们之前查过,如果缓存起来直接拉缓存即可,不用再去调用接口。
我们基于cached实现一个缓存异步纯函数的备忘录
const cachedAsync = function(fn) {
const cache = Object.create(null);
return async str => {
const hit = cache[str];
if (hit) {
return hit;
}
// 只缓存成功的Promise, 失败直接重新请求
return (cache[str] = await fn(str));
};
};
使用场景
const cachedAsyncQueryPrdList = cachedAsync(prdNo => {
// 下面是一个请求的操作,返回一个promise
return queryPrdList({
prdNo
});
});
<template>
<el-input v-model="prdNo" placeholder="请输入产品编码" @input="handleQueryPrdList" />
<el-select>
<el-option v-for="item in prdList" :label="item.label" :value="item.value">
</el-select>
</template>
<script>
export default {
data() {
prdNo: '',
prdList: [],
},
methods: {
async handleQueryPrdList() {
const { data } = await cachedAsyncQueryPrdList(this.prdNo);
this.prdList = data;
}
}
}
</script>
上面实现了,当输入相同的关键字,如果之前请求是成功的,直接拉起缓存,不会重新向服务器发起请求。因为我们的备忘录只会缓存成功的promise。
优化
针对上面的场景,虽然el-input底层已经使用compositionEnd和compositionStart事件来做一层防抖,只有文字真正输入到屏幕上才会去触发input事件。但是这是不够,如果用户输入手速很快,会出现一秒发几次请求的情况,增加了服务器负担。因此这种一般会搭配防抖函数使用。
防抖函数
const debounce = (fn, ms = 300) => {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), ms);
};
};
然后搭配我们的cachedAsync使用
const cachedAsyncQueryPrdList = cachedAsync(prdNo => {
// 下面是一个ajax请求的操作,返回一个promise
return queryPrdList({
prdNo
});
});
<template>
<el-input v-model="prdNo" placeholder="请输入产品编码" @input="debounceQueryPrdListFn" />
<el-select>
<el-option v-for="item in prdList" :label="item.label" :value="item.value">
</el-select>
</template>
<script>
const noop = () => {};
export default {
data() {
prdNo: '',
prdList: [],
debounceQueryPrdListFn: noop,
},
created() {
this.debounceQueryPrdListFn = debounce(this.handleQueryPrdList);
},
methods: {
async handleQueryPrdList() {
const { data } = await cachedAsyncQueryPrdList(this.prdNo);
this.prdList = data;
}
}
}
</script>
FBI WARNING: >>> cachedAsync函数,只适用于PURE函数。
这个实现已经在生产环境稳定使用,大家可以放心食用。
总结
到此这篇关于如何巧用Vue缓存函数的文章就介绍到这了,更多相关巧用Vue缓存函数内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论