preface
Hello everyone, I am Lin Sanxin, using the most easy to understand the most difficult knowledge points is my motto, the foundation is the premise of progress is my initial mind.
In retrospect, WHEN I first started writing, I was writing the Vue source code series, which is included in my nuggets column Vue source code parsing:
- “Vue source code learning (a)” you don’t know – data responsive principle
- Vue source code learning (2) “you don’t know – template compilation principle
- “Vue source code learning (three)” you don’t know – first render principle
- “Vue source code learning (4)” aims to write a study on the principle of computed and Watch that everyone can understand
- “Vue source code learning (5)” interviewers like to ask — Vue common method source analysis
- Do you want to know how Vuex works?
- Do you really know how a Slot is inserted
- 15 pictures, 20 minutes to understand the core principle of Diff algorithm, I said!!
- Lin Sanxin drew 8 diagrams, the most understandable Vue3 response core principle analysis
- 7 images, from zero to achieve a simple version of vue-Router, too easy to understand!
Today, let’s talk about the basic principle of keep-Alive, a common component in Vue.
scenario
Maybe you will often encounter such a scenario in your daily development: there is a List page list. vue that can be filtered, click a certain item to enter the corresponding details page, and wait until you return to list. vue from the details page, find that the List page has been refreshed! All the screening criteria are gone!!
keep-alive
What is?
keep-alive
Is aVue global components
keep-alive
It does not render itself and does not appear in the parent component chainkeep-alive
When dynamic components are wrapped, inactive components are cached rather than destroyed
How does it work?
Keep-alive receives three parameters:
include
: can passString, regular expression, array
Components whose names match are cachedexclude
: can passString, regular expression, array
Components whose names match are not cachedmax
: can passdigital
To limit the maximum number of cached components
Include and exclude are mostly passed to arrays
Dynamic components
<keep-alive :include="allowList" :exclude="noAllowList" :max="amount">
<component :is="currentComponent"></component>
</keep-alive>
Copy the code
Routing component
<keep-alive :include="allowList" :exclude="noAllowList" :max="amount">
<router-view></router-view>
</keep-alive>
Copy the code
The source code
Component based
As mentioned earlier, keep-alive is a Vue global component that takes three arguments:
include
: can passString, regular expression, array
Components whose names match are cachedexclude
: can passString, regular expression, array
Components whose names match are not cachedmax
: can passdigital
, limits the maximum number of cache components, exceedingmax
According toLRU algorithm
For replacement
By the way, let’s talk about what Keep-Alive does in its various life cycles:
created
: Initializes oneCache, keys,
, the former is used to store the virtual DOM collection of the cached component, and the latter is used to store the key collection of the cached componentmounted
: Real-time monitoringInclude and exclude
These two changes, and perform the corresponding operationsdestroyed
: Removes all cache-related stuff
As mentioned earlier, keep-alive is not rendered to the page, so abstract is crucial!
// src/core/components/keep-alive.js
export default {
name: 'keep-alive'.abstract: true.// Determine if this component needs to be rendered as a real DOM
props: {
include: patternTypes,
exclude: patternTypes,
max: [String.Number]},created() {
this.cache = Object.create(null) // Create an object to store the cached virtual DOM
this.keys = [] // Create an array to store cache keys
},
mounted() {
// Monitor include and exclude changes in real time
this.$watch('include'.val= > {
pruneCache(this.name= > matches(val, name))
})
this.$watch('exclude'.val= > {
pruneCache(this.name= >! matches(val, name)) }) },destroyed() {
for (const key in this.cache) { // Delete all caches
pruneCacheEntry(this.cache, key, this.keys)
}
},
render() {
/ / here}}Copy the code
PruneCacheEntry function
The lifecycle destroyed deletes all caches by calling pruneCacheEntry. So let’s talk about what pruneCacheEntry does
// src/core/components/keep-alive.js
function pruneCacheEntry (
cache: VNodeCache,
key: string,
keys: Array<string>, current? : VNode) {
const cached = cache[key]
if(cached && (! current || cached.tag ! == current.tag)) { cached.componentInstance.$destroy()// Execute the component's destory hook function
}
cache[key] = null / / set to null
remove(keys, key) // Delete the corresponding element
}
Copy the code
To sum up, we have done three things:
- 1. Iterate through the collection, executing all cache components
$destroy
methods - 2,
cache
The correspondingkey
Is set tonull
- 3, delete,
keys
The corresponding element in
Render function
Include is a whitelist, and exclude is a blacklist
The render function basically does these things:
- Step 1: Get it
keep-alive
The first component of the package and itsComponent name
- Step 2: Judge this
Component name
If I can beWhitelist, blacklist
Match, ifCan't be white list match | | match can be blacklisted
, directly returnsVNode
, do not go to the next step. If no, go to the next stepThe third step
- Step 3: According to
Component ID and tag
generateThe cache key
And looks in the cache collection to see if this component has been cached. If it has been cached, simply extract the cached component and update itThe cache key
inkeys
The position in (this isLRU algorithm
If not cached, continueThe fourth step
- Step 4: Separate in
Cache, keys,
Kept inThis component
And hisThe cache key
And check if the quantity exceedsmax
, more than the basisLRU algorithm
To delete - Step 5: Place the component instance
keepAlive
The property is set to true, which is very important, as we’ll see below!
// src/core/components/keep-alive.js
render() {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot) // Find the first child component object
constcomponentOptions: ? VNodeComponentOptions = vnode && vnode.componentOptionsif (componentOptions) { // Component parameters exist
// check pattern
constname: ? string = getComponentName(componentOptions)/ / component name
const { include, exclude } = this
if ( // Condition match
// not included(include && (! name || ! matches(include, name))) ||// excluded
(exclude && name && matches(exclude, name))
) {
return vnode
}
const { cache, keys } = this
constkey: ? string = vnode.key ==null // Define the component's cache key
// 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 (cache[key]) { // This component is already cached
vnode.componentInstance = cache[key].componentInstance
// make current key freshest
remove(keys, key)
keys.push(key) // Adjust the key sort
} else {
cache[key] = vnode // Cache component objects
keys.push(key)
// prune oldest entry
if (this.max && keys.length > parseInt(this.max)) { // If the number of caches exceeds the limit, delete the first one
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true // Hook functions are used to render and execute wrapped components
}
return vnode || (slot && slot[0])}Copy the code
Apply colours to a drawing
Vue: render Vue: render Vue: render Vue: render Vue: render Vue: render Vue: render Vue: render Vue
render
: This function converts the component toVNode
patch
This function will render the data directly on the first renderingVNode
Render directly intoReal DOM
“Will be picked up at the start of the second renderVNode
Will followOld VNode
Contrast, patch (diff algorithm contrast occurs at this stage), and then render intoReal DOM
Keep-alive itself renders
As mentioned earlier, the keep-alive component itself will not be rendered to the page. How does that work? If the value of abstract is true, the instance will be skipped and will not appear on the parent chain
// src/core/instance/lifecycle.js
export function initLifecycle (vm: Component) {
const options = vm.$options
// Find the first parent component instance that is not abstract
let parent = options.parent
if(parent && ! options.abstract) {while (parent.$options.abstract && parent.$parent) {
parent = parent.$parent
}
parent.$children.push(vm)
}
vm.$parent = parent
// ...
}
Copy the code
Package component rendering
Let’s talk more about how a component wrapped around keep-Alive uses the cache. VNode -> Real DOM takes place in patch, but this is also subdivided: VNode -> instantiate -> _update -> real DOM. The determination of the component to use the cache occurs during the instantiation phase, and this phase calls the createComponent function.
// src/core/vdom/patch.js
function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
let i = vnode.data
if (isDef(i)) {
const isReactivated = isDef(vnode.componentInstance) && i.keepAlive
if (isDef(i = i.hook) && isDef(i = i.init)) {
i(vnode, false /* hydrating */)}if (isDef(vnode.componentInstance)) {
initComponent(vnode, insertedVnodeQueue)
insert(parentElm, vnode.elm, refElm) // Insert the cached DOM (vnode.elm) into the parent element
if (isTrue(isReactivated)) {
reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm)
}
return true}}}Copy the code
- When loading the wrapped component for the first time, because
keep-alive
therender
Executes before the package component loads, so at this pointvnode.componentInstance
The value isundefined
And thekeepAlive
istrue
, the code goes toi(vnode, false /* hydrating */)
I’m not going to go down - When you access the wrapped component again,
vnode.componentInstance
The value of is the component instance that has been cached, then it will executeinsert(parentElm, vnode.elm, refElm)
Logic, which inserts the last DOM directly into the parent element.
conclusion
I am Lin Sanxin, an enthusiastic front-end novice programmer. If you progress, like the front end, want to learn the front end, then we can make friends, touch fish ha ha, touch fish, point this –> touch fish boiling point
reference
- The keep-alive principle is thoroughly revealed
- Reveal the Vue technology | keep alive
- Vue source