The article was first published on a personal blog
Keep the usage – the alive
Let’s take a look at the official documentation for the use of keep-alive.
<keep-alive>
<component :is="view"></component>
</keep-alive>
Copy the code
-
props:
- Include: Only components whose names match are cached
- Exclude: Any component whose name matches will not be cached
- Max: Maximum number of component instances that can be cached. (Added in 2.5.0, once this number is reached, the cached component instances that have not been accessed for the longest time are destroyed before new instances are created.)
-
usage
- When keep-alive wraps dynamic components, it caches inactive component instances rather than destroying them.
- When a component is switched in keep-alive, its activated and deactivated lifecycle hook functions are executed.
Realize the principle of
The source code parsing
is a component of vue source code, we can start from the source analysis, based on vue 2.6.11 version, source location SRC /core/components/keep-alive.js
The implementation of the
component is also an object
export default {
name: 'keep-alive'.// Abstract the component
abstract: true.props: {
// Only components with matching names are cached
include: patternTypes,
// Any component with a matching name will not be cached
exclude: patternTypes,
Since we cache vNode objects, it also holds the DOM. When we cache a lot, it takes up memory, so this configuration allows us to specify the cache size
max: [String.Number]
},
created () {
// Initialize the cache object that stores the cache and the array of cache vNode keys
this.cache = Object.create(null)
this.keys = []
},
Destroy all component instances in cache
destroyed () {
for (const key in this.cache) {
pruneCacheEntry(this.cache, key, this.keys)
}
},
mounted () {
// Listen for include and exclude changes and readjust the cache contents as they change
If the new rule does not match the name of the node in the cache, remove the node from the cache
this.$watch('include', val => {
pruneCache(this, name => matches(val, name))
})
this.$watch('exclude', val => {
pruneCache(this, name => ! matches(val, name)) }) },// Customize the render function
render () {
Since we also write the DOM inside the
tag, we can get its default slot first, and then get its first child.
handles only the first child, so keep in mind that * is usually paired with component dynamic components or router-views. * /
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
constcomponentOptions: ? VNodeComponentOptions = vnode && vnode.componentOptionsif (componentOptions) {
// check pattern
// Determine the relationship between the current component name and include and exclude:
constname: ? string = getComponentName(componentOptions)const { include, exclude } = this
Matches matches arrays, strings, and regular expressions
// The vNode of this component is returned directly if the component name includes and does not match, or if the component name includes and does not match, or if the component name includes and does not match, otherwise, the next step is cache:
if (
// not included(include && (! name || ! matches(include, name))) ||// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
constkey: ? string = vnode.key ==null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? componentOptions.Ctor.cid + (componentOptions.tag ? ` : :${componentOptions.tag}` : ' ')
: vnode.key
// If the cache is hit, the vNode component instance is fetched directly from the cache, and the key order is rearranged to be the last one
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
// Use the LRU cache strategy to remove the key and add it to the end
remove(keys, key)
keys.push(key)
} else {
// If there is no cache hit, set vNode to cache
cache[key] = vnode
keys.push(key)
// prune oldest entry
// If Max is configured and the cache length exceeds this. Max, the first object is removed from the cache
if (this.max && keys.length > parseInt(this.max)) {
In addition to removing the cached component from the cache, determine if the cached component tag to be removed is not the currently rendered component tag, and perform the $destroy method to remove the cached component instance.
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
// keepAlive flag bit
vnode.data.keepAlive = true
}
return vnode || (slot && slot[0])}}function pruneCacheEntry (cache: VNodeCache, key: string, keys: Array
, current? : VNode
) {
const cached = cache[key]
if(cached && (! current || cached.tag ! == current.tag)) { cached.componentInstance.$destroy() } cache[key] =null
remove(keys, key)
}
Copy the code
1. Determine whether the current component is to be cached
Get the first child of the keep-alive package and its component name, and then match the included /exclude(if any) to determine whether to cache the package. If not, the component instance is returned directly
2. If the key matches the cache, the cache is directly obtained and the key location is updated
Key is generated based on the component ID and tag, and the cache object is checked to see if the component instance object has been cached. If so, the cache value is directly fetched and the key position in this.keys is updated (updating the key position is the key to implement the LRU replacement strategy).
3. If the cache does not match, set it to the cache and check whether the number of cached instances exceeds the Max value
Cache object, then check if the number of cached instances exceeds the value of Max. If the number exceeds the value of Max, delete the most recent and longest unused instance (i.e. the key with subscript 0) according to the LRU substitution policy.
4. Set the keepAlive property of the current component instance to true, which is used during cache selection.
Abstract (Abstract component)
Abstract is an abstract component: it does not render a DOM element on its own and does not appear in the parent component chain.
Created, Mounted and other hook functions are not executed when a component is rendered once it is cached. However, some business scenarios need to do something when a cached component is re-rendered, and VUE provides activated and deactivated hook functions.
When vUE initializes the life cycle, it determines whether to ignore a component based on the abstract attribute when establishing parent-child relationships for component instances. In keep-alive, if abstract:true is set, Vue skips the component instance.
export function initLifecycle (vm: Component) {
const options = vm.$options
// locate first non-abstract parent
let parent = options.parent
if(parent && ! options.abstract) {while (parent.$options.abstract && parent.$parent) {
parent = parent.$parent
}
parent.$children.push(vm)
}
...
}
Copy the code
<keep-alive>
First render and cache render
For the first rendering, the process is the same as for normal components, except for setting the cache in
and setting vnode.data.keepAlive to true.
When I cache the render, Created and Mounted components are not executed according to vnode.ponentInstance (undefined) and vnode.data.keepAlive And other hook functions, but to perform the patch process of cached components, and finally directly insert the cached DOM object into the target element, complete the rendering process in the case of data update.
Caching strategies
LRU cache strategy: Replace the most unused data in memory with new data. The LRU (Least Rencently Used) algorithm weeds out data based on the historical access records of the data. The core idea is that “if the data has been accessed recently, it is more likely to be accessed in the future”.
The most common implementation is to use a linked list to store cached data. The detailed algorithm is as follows:
- New data is inserted into the linked list header
- Whenever a cache hit (that is, cached data is accessed), the data is moved to the head of the linked list
- When the list is full, discard the data at the end of the list.
conclusion
<keep-alive>
Is an abstract component,- Set the cache for the first rendering
- Created, Mounted and other hook functions are not implemented during cache rendering. Instead, patch is performed on cached components and the target element is directly updated.
- The component is cached using the LRU cache policy
- If the cache is hit, the cache is directly returned and the location of the cache key is updated
- If no, set it to the cache and check whether the number of instances in the cache exceeds Max
reference
- Vue keep-alive implementation principle and cache strategy
- The implementation principle of KEEP-alive and LRU cache algorithm in Vue are analyzed
- Cache elimination algorithm -LRU algorithm
- Leetcode146. LRU caching mechanism
other
Recently, WE launched a 100-day front-end advanced plan, which is mainly to dig into the principle behind each knowledge point. Welcome to follow the wechat public account “Mucode star”, and we will study together and punch the clock for 100 days.