1. The fate of the past life
The design idea of the built-in component keep-alive in vue originates from the Keep-Alive mode in HTTP. The Keep-Alive mode avoids frequent creation and destruction of links, allowing multiple requests and responses to use the same HTTP link.
Keep-alive is turned off by default in HTTP 1.0. You need to add "Connection: Keep-Alive" to the HTTP header to enable Keep-Alive; Keep-Alive is enabled by default in HTTP 1.1. If "Connection: close" is added, it will be turned off. Currently, most browsers use the HTTP 1.1 protocol.
2. Keep-alive built-in components
Function: Cache component instances when switching components dynamically to avoid dom re-rendering.
1. Cache dynamic components
When the component iscomponentOne
caches the component instance
<keep-alive :include="componentOne`" :exclude="componentTwo" :max="num"> <component :is="currentComponent"></component> </keep-alive>
2. Cache routing components
Note that there is a difference between cache routing components, and the usage is as follows:
<keep-alive :include="componentOne`" :exclude="componentTwo" :max="num"> <router-view :is="currentComponent"></router-view> </keep-alive>
The usage is as follows:
<router-view v-slot="{ Component }"> <keep-alive :include="includeList"> <component :is="Component"/> </keep-alive> </router-view>
3. Principle analysis
The cached components are recorded in the form of [key, vnode], and keys record the cached component key, according to the included and exclude values, and clear according to the LUR algorithm when the set max exceeds the set. Not much different from that.
(1) What does keep-alive do in its life cycle?
- created: Initialize catch, keys. catch is an array that caches component virtual doms, where the key of the object in the array is the component's key, and value is the component's virtual dom; keys are an array used to cache component's keys.
- mounted: listen to changes in include and exclude attributes in real time and perform corresponding operations.
- destroyed: Delete all cache-related data.
(2) Source code
address:Source code address
// Source code location: src/core/components/export default { name: 'keep-alive', abstract: true, props: { include: patternTypes, exclude: patternTypes, max: [String, Number] }, created () { = (null) = [] }, destroyed () { for (const key in ) { pruneCacheEntry(, key, ) } }, mounted () { // Check whether there is a cache without a cache, and then go to the cache directly () // Here we use watch to monitor include and exclude // If there is any change, update according to the latest include and exclude // Remove cached vnodes that do not meet the include and exclude restrictions from this.$watch('include', val => { pruneCache(this, name => matches(val, name)) }) this.$watch('exclude', val => { pruneCache(this, name => !matches(val, name)) }) }, updated() { () }, methods:{ cacheVNode() { const { cache, keys, vnodeToCache, keyToCache } = this if (vnodeToCache) { const { tag, componentInstance, componentOptions } = vnodeToCache cache[keyToCache] = { name: _getComponentName(componentOptions), tag, componentInstance } (keyToCache) // prune oldest entry if ( && > parseInt()) { pruneCacheEntry(cache, keys[0], keys, this._vnode) } = null } } }, render(){ //Introduction below } }
(3)abstract:true
When set to true, the component on the surface is an abstract component. The abstract component will not establish a parent-child relationship with the child component. The component instance will decide whether to ignore the component based on this attribute, so there will be no node rendering on the page.
(4) pruneCacheEntry function
All cached components are looped in the destoryed cycle and usedpruneCacheEntry
To handle it, what does pruneCacheEntry do?
// src/core/components/ function pruneCacheEntry ( cache: VNodeCache, key: string, keys: Array<string>, current?: VNode ) { const cached = cache[key] if (cached && (!current || !== )) { .$destroy() // Execute the component's destory hook function } cache[key] = null // The key of the object in cache is set to null remove(keys, key) // Delete the elements corresponding to keys}
During the destoryed cycle, delete all arrays of cache components.pruneCacheEntry
Mainly doing these things:
- Iterate through the cached component collection (cach) and execute the $destroy method on all cached components
- Clear the value of the key in the cache
- Clear keys in keys
(5)render
What is mainly done in render?
- Get the vnode, componentOptions, name of the first component in the keep-alive component child node
- If the name exists and is not in include or exists in exclude, a virtual dom is returned. At this time, the component does not use the cache.
- Next is the else situation above: use keep-alive for component cache, generate component keys based on component id and tag. If there is a vdom with key as the attribute name in the cache collection, it means that the component has been cached, then assign the cached Vue instance to , delete the key from the keys, and then push the key to the keys to ensure that the current key is at the end of the keys (this is the key of the LRU algorithm). If it does not exist, continue to walk below
- If cache[key] does not exist, the component is loaded for the first time, then the vdom is assigned to cache[key] and the key pushes to the key
- If the length of keys is greater than max, component cache cleaning will be performed, and the components cached infrequently used will be removed. The pruneCacheEntry method is also called
render () { // Get the first component vnode in the keep-alive component child node const slot = this.$ const vnode = getFirstComponentChild(slot) // Get the component's configuration option object const componentOptions = vnode && if (componentOptions) { // Get the name of the component const name = _getComponentName(componentOptions) const { include, exclude } = this // If the current component name is not in include or the component's name is in exclude // It means that the current component is not cached by keep-alive. At this time, just return vnode directly if ( // not included (include && (!name || !matches(include, name))) || // excluded (exclude && name && matches(exclude, name)) ) { return vnode } // The code execution ends here, indicating that the current component is cached by the keep-alive component const { cache, keys } = this // Define the key used for vnode cache const key = == null ? // same constructor may get registered as different local components // so cid alone is not enough (#3269) + ( ? `::${}` : '') : // If cache[key] already exists, it means that the current component vnode has been cached, and it needs to be restored and restored at this time if (cache[key]) { // Assign cached Vue instances to = cache[key].componentInstance // make current key freshest // Remove the key from the keys first, and then push the key, which ensures that the current key is at the end of the keys array remove(keys, key) (key) } else { // delay setting the cache until update // If cache[key] does not exist, it means that the current child component appears for the first time. At this time, vnode needs to be cached into cache and keys are stored in the keys string array. Here is an intermediate variable to receive, and when the data changes, update is triggered to call the cacheVNode method. = vnode = key } // @ts-expect-error can can be undefined // Set the property to true, which has a function of identifying vnode, identifying this // vnode is the render function of the keep-alive component. This identifier is useful in the following running code = true } return vnode || (slot && slot[0]) }
3. LRU algorithm
When clearing the cached components, the LRU algorithm is used. What is the specific strategy?When the data exceeds the limited space, the principle of cleaning is to clear data that has not been used for a long time.。
This is the end of this article about the analysis of keep-alive source code. For more related keep-alive source code content, please search for my previous articles or continue to browse the related articles below. I hope everyone will support me in the future!