前端性能优化篇—KeepAlive苹果手机中的墓碑机制

738 阅读4分钟

各位看官别急,今天了解的是Vue中内置组件KeepAlive,这也是前端面试中性能优化中的重难点

曾经作为一名安卓用户,我习惯了杀后台,因为后台占用了手机的内存资源。后面我姐给我一台苹果手机后,我也习惯于杀后台,直到有一天有人跟我说苹果不需要杀后台。

image.png

为啥IOS系统不要杀后台?难不成内藏玄鸡???

然后我就知道了原来是IOS有一个墓碑机制,那啥是墓碑机制呢?

iOS的墓碑机制并不是进入后台就把app杀掉,而是进入后台后,会有一个缓冲时间给app做background处理准备进入休眠,缓冲时间之后app的所有未注册的动作都将被禁止,iOS自己会根据情况允许你适时的回调,这就是墓碑。当下次app进入前台时,系统会从内存中读取上次缓存的app状态,甚至可以做到连interval都停住的状态。


没有用到KeepAlive的两个组件,当刷新页面时数据丢失。

屏幕录制 2024-08-02 1549 -small-original.gif

用了KeepAlive的两个组件,当切换组件实例时不会丢失数据

屏幕录制 2024-08-02 1556 -small-original.gif

在开发过程中,我们难免会碰到这样一种情况。默认情况下,一个组件实例在被替换掉后会被销毁。这会导致它丢失其中所有已变化的状态——当这个组件再一次被显示时,会创建一个只带有初始状态的新实例。

而在我们实际使用中,例如抖音刷个视频,如果有人给你发消息或者私信你,你去点击消息页面并且回复了他,这就切换了组件,然后你跳回首页刷视频给你刷新了页面,你发现你正在看的视频没了,这肯定是不行的。而且对于性能消耗来说,重新加载了资源肯定是很浪费资源的。如果说这时候能有一个墓碑机制去冻结我们切换页面的组件,等我们再返回时去获取上一次的缓存而不用重新加载资源。

Vue中的内置了[KeepAlive组件](KeepAlive | Vue.js (vuejs.org))做了这样的事情。

KeepAlive

KeepAlive 是 Vue.js 提供的一个内置组件,用于缓存动态组件,以提高应用性能。通过将组件包裹在 KeepAlive 组件中,Vue 可以在组件被切换时保持其状态,并避免重新渲染。KeepAlive 主要用于带有频繁切换的视图组件,如标签页或动态路由。

Props

KeepAlive 组件提供了一些有用的 props,可以进一步控制组件的缓存行为:

  • include: 一个字符串或正则表达式,匹配的组件会被缓存。包括在内的。
  • exclude: 一个字符串或正则表达式,匹配的组件不会被缓存。排除在外的。
  • max: 一个数字,指定最多可以缓存多少组件实例。

注意点:在 Vue 中使用 KeepAlive 组件时,如果 includeexclude 属性同时存在,exclude 的优先级更高。这意味着,即使一个组件匹配 include 规则,如果它也匹配 exclude 规则,它仍然不会被缓存。 具体来说,如果一个组件的名字同时满足 includeexclude 规则,exclude 规则会覆盖 include 规则,使得该组件不被缓存。

示例

<keep-alive include="viewA">
  <component :is="currentView"></component>
</keep-alive>

<keep-alive :include="['viewA', 'viewB']">
  <component :is="currentView"></component>
</keep-alive>

<keep-alive :exclude="/^view/">
  <component :is="currentView"></component>
</keep-alive>

<keep-alive :max="10">
  <component :is="currentView"></component>
</keep-alive>

在这些示例中,includeexclude props 用于指定哪些组件应该被缓存,哪些不应该被缓存。max prop 用于限制缓存的组件实例数量。

事件

KeepAlive 组件还提供了一些事件,可以在组件激活和停用时触发:

  • activated: 当组件实例被激活时触发。
  • deactivated: 当组件实例被停用时触发。

示例

<template>
  <div>
    <keep-alive @activated="onActivated" @deactivated="onDeactivated">
      <component :is="currentView"></component>
    </keep-alive>
  </div>
</template>

<script>
export default {
  methods: {
    onActivated() {
      console.log('Component activated');
    },
    onDeactivated() {
      console.log('Component deactivated');
    }
  }
}
</script>

通过使用这些事件,可以在组件状态变化时执行特定的逻辑。

KeepAlive的高级用法

与router结合使用

<template>
    <div>
        <router-view v-slot="{Component}">
            <keep-alive :include="cachedComponents">
                <component :is="Component" />
            </keep-alive>
        </router-view>
        <div class="footer h-12">
            <TabBar class="fixed bottom-0" />
        </div>
    </div>
</template>
<script setup lang="ts">
import TabBar from '@/views/layout/TabBar.vue'
import { computed } from 'vue'
import { useRouter } from 'vue-router'
const router = useRouter();

const cachedComponents = computed(() => {
    return router.getRoutes()
        .filter(route => route.meta.cache)
        .map(route => route.name)
})
</script>

分析:

    1. 用v-slot写了一个具名插槽,挖了一个坑,去填充component里的内容
    1. include去写需要被缓存的组件
    1. tailwindcss原子化的css,class="footer h-12" 直接在类名内写样式
    1. router.getRoutes()获取所有路由信息,拿取route里meta中cache的值去判断这个组件是否要被缓存

在路由配置文件中加入meta对象中加入cache属性去判断是否要被缓存

{
        path:'home',
        name:'Home',
        component: () => import('@/views/Home/Home.vue'),
        meta:{
            cache:true
        }

    },
    {
        path: 'discount',
        name: 'Discount',
        meta: {
            cache: false
        },
        component: () => import('../views/Discount/Discount.vue')
    },

这些就是我对于KeepAlive的理解,利用它能够性能优化,让本不需要重新加载的资源不重新加载,也防止丢失数据。 如果这对你有帮助,不妨点个免费的赞。

R-C.gif