文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

vue2.x中keep-alive源码解析(实例代码)

2023-02-14 12:02

关注

一、前世尘缘

vue中内置组件keep-alive的设计思想源于HTTP中的Keep-Alive模式,Keep-Alive模式避免频繁创建、销毁链接,允许多个请求和响应使用同一个HTTP链接。
HTTP 1.0 中keep-alive默认是关闭的,需要在HTTP头加入"Connection: Keep-Alive",才能启用Keep-Alive;HTTP 1.1中默认启用Keep-Alive,如果加入"Connection: close ",才关闭。目前大部分浏览器都是用HTTP 1.1协议。

二、keep-alive内置组件

作用:动态切换组件时缓存组件实例,避免dom重新渲染。

1.缓存动态组件

当组件为componentOne时缓存该组件实例

<keep-alive :include="componentOne`" :exclude="componentTwo" :max="num"> 
    <component :is="currentComponent"></component> 
</keep-alive>

2.缓存路由组件

注意缓存路由组件vue2.x与vue3.x有区别,vue2.x用法如下:

<keep-alive :include="componentOne`" :exclude="componentTwo" :max="num"> 
    <router-view :is="currentComponent"></router-view> 
</keep-alive>

vue3.x用法如下:

<router-view v-slot="{ Component }">
   <keep-alive :include="includeList">
	    <component :is="Component"/>
   </keep-alive>
</router-view>

3.原理解析

缓存的组件以 [key,vnode] 的形式记录,keys记录缓存的组件key,依据inclued、exclude的值,并且当超过设置的max根据LUR算法进行清除。vue2.x和vue3.x相差不大。

(1)keep-alive 在生命周期中做了什么?

(2)源码

地址:源码地址

// 源码位置:src/core/components/keep-alive.js
export default {
  name: 'keep-alive',
  abstract: true,
  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },
  created () {
    this.cache = Object.create(null)
    this.keys = []
  },
  destroyed () {
    for (const key in this.cache) {
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },
  mounted () {
   //查看是否有缓存没有缓存的话直接走缓存
    this.cacheVNode()
    // 这里借助 watch 监控 include  和 exclude 
  // 如果有变化的话,则按照最新的 include 和 exclude 更新 this.cache
  // 将不满足 include、exclude 限制的 缓存vnode 从 this.cache 中移除  
  this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },
  updated() {
    this.cacheVNode()
  },
  methods:{
   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
      }
    }
 },
  render(){
    //下面详细介绍
  }
}

(3)abstract:true

设置为true时,表面该组件为抽象组件,抽象组件不会和子组件建立父子关系,组件实例会根据这个属性决定是否忽略该组件,所以并不会有节点渲染在页面中。

(4)pruneCacheEntry函数

destoryed周期中循环了所有缓存的组件,并用 pruneCacheEntry进行处理,pruneCacheEntry做了什么事?

// 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() // 执行组件的destory钩子函数
  }
  cache[key] = null  // cache中对象的key设为null
  remove(keys, key) // 删除keys对应的元素
}

destoryed周期中,删除缓存组件的所有数组,pruneCacheEntry主要做了这几件事:

(5)render

render中主要做了什么?

render () {
	// 获取 keep-alive 组件子节点中的第一个组件 vnode
    const slot = this.$slots.default
    const vnode = getFirstComponentChild(slot)
    // 获取组件的配置选项对象
    const componentOptions = vnode && vnode.componentOptions
    if (componentOptions) {
      // 获取组件的名称
      const name = _getComponentName(componentOptions)
      const { include, exclude } = this
       // 如果当前的组件 name 不在 include 中或者组件的 name 在 exclude 中
		  // 说明当前的组件是不被 keep-alive 所缓存的,此时直接 return vnode 即可
      if (
        // not included
        (include && (!name || !matches(include, name))) ||
        // excluded
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }
     // 代码执行到这里,说明当前的组件受 keep-alive 组件的缓存
      const { cache, keys } = this
        // 定义 vnode 缓存用的 key
      const key =
        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
           // 如果 cache[key] 已经存在的话,则说明当前的组件 vnode 已经被缓存过了,此时需要将其恢复还原出来
      if (cache[key]) {
      	// 将缓存的 Vue 实例赋值给 vnode.componentInstance
        vnode.componentInstance = cache[key].componentInstance
        // make current key freshest
        	// 先从 keys 中移除 key,然后再 push key,这可以保证当前的 key 在 keys 数组中的最后面
        remove(keys, key)
        keys.push(key)
      } else {
        // delay setting the cache until update
        	// 如果 cache[key] 不存在的话,说明当前的子组件是第一次出现,此时需要将 vnode 缓存到 cache 中,将 key 存储到 keys 字符串数组中。这里是用一个中间变量接收,当数据变化时触发updated去调用cacheVNode方法。
        this.vnodeToCache = vnode
        this.keyToCache = key
      }

      // @ts-expect-error can vnode.data can be undefined
       // 将 vnode.data.keepAlive 属性设置为 true,这对 vnode 有一个标识的作用,标识这个
		  // vnode 是 keep-alive 组件的 render 函数 return 出去的,这个标识在下面的运行代码中有用
      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }

三、LRU算法

缓存的组件在进行清除的时候使用了LRU算法,具体是什么策略呢?当数据超过了限定空间的时候对数据清理,清理的原则是对很久没有使用到过的数据进行清除

到此这篇关于vue2.x中keep-alive源码解析的文章就介绍到这了,更多相关vue2.x keep-alive源码内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯