大家好,我是Kason。在前几天写的一篇介绍use新钩子的文章中,讲到了React是如何原生实现一个缓存功能的——cache。对于下面的代码,多次调用cache包裹的函数时,如果传递的参数不变,则一直返回cache的值:constcacheFn=cache(fn);cacheFn(1,2,3);//不会执行fn,直接返回缓存值cacheFn(1,2,3);为什么React需要cache方法?考虑以下组件:constfetch=cache(fetchUserData);functionUser({id}){const{name}=use(fetch(id));return
{name}
;}User组件会根据Userid请求用户数据,并渲染用户名。如果id改变了,fetch方法重新发起请求是正常逻辑。然而,React组件经常被渲染。在id不变的情况下,由于User组件的渲染而不断发起请求,显然是不合理的。因此,在这种情况下,缓存方法是必需的。当id不变时,即使重复渲染User组件,fetch(id)返回相同的值。这篇文章会讲缓存的源码实现。实现思路分析整个方法实现共有64行代码。首先分析一下实现的要点。如果参数未更改,则使用缓存的值。这意味着我们需要处理:参数的顺序例如,当参数的顺序发生变化时,不使用缓存值:constcacheFn=cache(fn);缓存Fn(1,2,3);//不使用缓存值cacheFn(3,2,1);区分引用类型和原始类型参数。例如,当相同位置的参数传递相同的引用类型值时,返回缓存值:constcacheFn=cache(fn);constobj={};cacheFn(1,obj,3);//返回缓存值cacheFn(1,obj,3);当同一位置的参数传递不同的引用类型值时,不会返回缓存值:constcacheFn=cache(fn);常量对象={};cacheFn(1,obj,3);//不返回缓存值cacheFn(1,{},3);缓存垃圾回收缓存数据时,注意“缓存失效但引用数据未释放”导致内存泄漏。所以,对于引用类型的数据,可以使用WeakMap来保存。对于原始类型的数据,可以使用Map来保存。WeakMap和Map的区别在于——在WeakMap中,其对应值的键是弱引用。这意味着当没有其他数据引用该键时,它可以被垃圾回收。在Map中,keytovalue是强引用,即使没有其他数据引用这个key,也不会被垃圾回收。实现原理本文不介绍具体的代码实现(一大段代码贴出来让人看着头疼)。我将通过示例图来解释实现原理。了解原理后,如果对实现细节感兴趣,可以参考:缓存源码实现PR[1]缓存在线示例[2]如下代码:constcacheFn=cache(fn);constobj={};cacheFn(1,obj,3);cacheFn的每个传参都对应缓存内部的一个cacheNode节点://CacheNode构造函数createCacheNode