JavaScript
如何巧用Vue缓存函数浅析
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缓存函数内容请搜索 以前的文章或继续浏览下面的相关文章希望大家以后多多支持 !