Keep-alive is used to cache components in vue
Let’s start with a simple article map:
1. What role does keep-alive play in VUE
Let’s take a look at some of the features of Keep-Alive:
When switching between components, you sometimes want to keep the state of those components to avoid performance issues caused by repeated rerendering.
Keep-alive can be used to cache dynamic components
- Component reuse improves performance
- Cache less-used components instead of destroying them directly
2. How to use the actual project
2.1 In normal cases, components jump
Dynamic routing is often used in projects. Here’s an example:
Create a new project using vue create hello-world. Create a new project using vue create hello-world. Create a new project using vue create hello-world. The destroyed() function destroys the component and the data is lost when we try to switch the component.
The following codeApp.vue:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
Copy the code
The router/index. Js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '.. /views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/'.name: 'Home'.component: Home
},
{
path: '/about'.name: 'About'.// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () = > import(/* webpackChunkName: "about" */ '.. /views/About.vue')}]const router = new VueRouter({
routes
})
export default router
Copy the code
view/about.vue:
<template>
<div class="about">
<input type="text">
</div>
</template>
<script>
export default {
name:"about".destroyed() {
console.log('Component destroyed')}}</script>
Copy the code
view/home.vue:
<template>
<div class="home">
<input type="text">
</div>
</template>
<script>
export default {
name: 'home'.destroyed() {
console.log('Component destroyed')}}</script>
Copy the code
2.2 Using keep-alive to cache components
When jumping a component, it can cache the previous component without destroying it
Just modify the app.vue component above:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<keep-alive>
<router-view />
</keep-alive>
</div>
</template>
Copy the code
2.3 Keep-alive Controls whether components are cached
In the actual project development, we may need a specific project to cache, so how to achieve this through keep-alive?
The keep-alive parameters are as follows:
- Include: [String,RegExp,Array] Only matched components can be cached
<keep-alive include="home">
<router-view />
</keep-alive>
Copy the code
- Exclude: [String,RegExp,Array] Matching components are not cached
<keep-alive include="about">
<router-view />
</keep-alive>
Copy the code
- Max: [String,Number] The maximum Number of component instances that can be cached. The least used instance in the cache is destroyed before a new instance is created
3. How to cache the source code in keep-alive
The source code is here:
The cacheVNdoe and lifecycle hook Render functions are analyzed below (mostly in comments).
3.1 cacheVNode ()
cacheVNode() {
const { cache, keys, vnodeToCache, keyToCache } = this
if (vnodeToCache) {
const { tag, componentInstance, componentOptions } = vnodeToCache
cache[keyToCache] = {
name: getComponentName(componentOptions),
tag,
componentInstance,
}
keys.push(keyToCache)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
this.vnodeToCache = null}}Copy the code
3.2 created () :
Define two properties
this.cache = Object.create(null)
this.keys = []
Copy the code
This. cache is an object used to store components that need to be cached
this.cache = {
'key1':Components' 1 '.'key2':'component 2',,,,}Copy the code
This. Keys is an array that stores the keys of each component that needs to be cached.
3.3 destoryed ()
The hook iterates through the this.cache object and destroys any cached components that are not currently being rendered, removing them from this
destoryed() {
for (const key in this.cache) {
pruneCacheEntery(this.cache,key,this.keys); }}function pruneCacheEntery(cache,key,keys,current) {
const cached = cache[key]
if(cached &&& (! current || cached.tag ! == current.tag)) { cached.componentInstance.$destory() } cache[key] =null
remove(keys,key)
}
Copy the code
3.4 mounted ()
In Mounted, observe the change of include exclude
mounted () {
this.$watch('include'.val= > {
pruneCache(this.name= > matches(val,name))
})
this.$watch('exclude'.val= > {
pruneCache(this.name= >! matches(val,name)) }) }Copy the code
3.5 render ()
How to cache keep-alive
- Gets the node of the first child component
const slot = this.$solts.default
const vnode = getFirstComponentChild(solt)
Copy the code
Only the first child is handled, so it is usually paired with a Component dynamic component or router-view.
- Gets the name of the component node
/* Get the name of the component node */
const name = getComponentName(componentOptions)
/* Get the component's name field first, or the component's tag */ if name does not exist
function getComponentName (opts: ? VNodeComponentOptions): ?string {
return opts && (opts.Ctor.options.name || opts.tag)
}
Copy the code
- Match the component name with the general configuration rule in include Exclude
- If name does not match the index rule or exclude rule, the component is not cached and the vNode of the component is returned
const { include, exclude } = this
if( (include && (! name || ! matches(include, name))) || (exclude && name && ! matches(exclude,name)) ) {return vnode
}
Copy the code
- Otherwise cache
const { cache, keys } = this
// Get the key of the component
const key = vnode.key == null?
componentOptions.Ctor.cid + (componentOptions.tag ? ` : :${componentOptions.tag}` : ' ')
: vnode.key
// Select this. Cach from this. Cach to see if this value exists
/* If the cache is hit, the vNode component instance is fetched directly from the cache */
if (cache[key]) {
vnode.componentInstance = cache[key].componentInstance
/* Rearrange the order of the component keys, remove them from their original place and put them back in the last */
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
/* If Max is configured and the cache length exceeds this. Max, the first */ is removed from the cache
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
// If not, the component is cached
Copy the code
LRU is the least recently used
When keep-alive is used, the component does not create or mounted. However, the value of activated and deactivated hook functions need to be used to perform operations in the component. The two hook functions can be invoked when the component is activated or deactivated
4. LRU caching
Adjust the order of the component key, delete it from the original place and put it back. In the comment above, there is a sentence: delete the node that is now used from the original place and put it back.
In fact, this is the core of the LRU cache mechanism. LRU (Least recently used) algorithm eliminates data according to the historical access record of data. The core idea is that “if data has been accessed recently, the probability of being accessed in the future is higher”.
Finally, finally, a force buckle algorithm: The LRU cache
var LRUCache = function(capacity) {
this.size = capacity // Cache size
this.map = new Map(a)// Use map as the cache structure
};
// There are two methods on LRUCache's prototype object: get and PUT
LRUCache.prototype.get = function(key) {
// If the value obtained by get was already in the map, delete it, add it back, and return the value
if(this.map.has(key)){
let value = this.map.get(key) // Cache values first
this.map.delete(key) / / delete
this.map.set(key, value) // rejoin
return value
} else { // There is no direct return -1
return -1}};// If it already exists, delete it and add it to the list.
// If it does not already exist, add it again.
// If the value exceeds the specified value,
// Delete the map that has not been used for the longest time, and then add the value that needs to be added.
LRUCache.prototype.put = function(key, value) {
if(this.map.has(key)){ // Delete it
this.map.delete(key)
}
this.map.set(key, value) / / to join
if(this.map.size > this.size){ // Delete the first one
// Find the first item in the map
this.map.delete(this.map.keys().next().value)
}
};
Copy the code
5. To summarize
- Keep-alive is a built-in component of Vue that controls the cache of components. It can set three parameters to determine which components need to be cached or not, as well as the maximum cache size
- In the analysis of keep-Alive cache strategy, LRU cache elimination strategy is used.
- The core of the LRU cache strategy is that the data that is accessed (read or modified) each time is expected to be used with the greatest probability and therefore needs to be processed
The above are some summaries and generalizations about keep-alive
Comment section if you have any questions