keep-alive和js预加载技术

442 阅读3分钟

keep-alive

生命周期

keep-alive的页面: 第一次进入:created-> mounted-> activated,退出:deactivated。
再次进入,触发activated(这时我们可以拿到组件的所有data,可在此节点做一些请求更新页面数据)

keep-alive不生效实例

// router设置
{
    path: '/list'name: 'List',
    component: () => import('@/views/order/list'),
    meta: {keepAlive: true}   // 设置页面缓存,保持tab状态
    },
    {
    path: '/detail'name: 'Detail',
    component: () => import('@/views/order/detail'),
    meta: {keepAlive: false}   // 不需要缓存
},
// 页面配置,v-if的位置避免页面不缓存问题
<keep-alive :include="keepAliveView">
    <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
// 设置需要缓存的白名单
<script>
export default {
    data(){
        return {
            keepAliveView:'',  //需要缓存的组件名称列表,用逗号分隔
        };
    },
    created(){
        this.getKeepAliveView();
    },
    methods:{
        getKeepAliveView(){  //每一帧都获取可缓存列表,防止前进时设置缓存会慢一步
            const self = this;
            requestAnimationFrame(function func(){
                let list = self.$router.options.routes.filter(item=>{
                    return item.meta.myKeepAlive;
                }).map(item=>{
                    return item.component.name;  //这里使用的是组件名。keep-alive是根据组件名判断展示那个组件,如果组件名和路由配置的名称一样可以直接写 item.name (如果配置了路由懒加载的话没有component.name)
                });
                self.keepAliveView = "," + list.join(",");  //必须首部加逗号。
                requestAnimationFrame(func);
            });
        },
    },
}
</script>


需求是前进缓存,后退清除缓存

场景 Vue中前进刷新,后退缓存用户浏览数据

列表页面 =>点击进入详情页=> 后退到列表页 要缓存列表原来数据

重新进入列表页面 => 获取最新的数据

//添加全局路由守卫,用来判断页面前进或是后退
router.beforeEach((to, from, next) => {  //页面跳转后添加时间戳参数
    if (typeof to.query._t !== "undefined") {
        next();
    } else {
        to.query._t = new Date().getTime().toString();
        next(to);
    }
});

在需要用到的地方

watch:{
    $route(to,from){  //当页面返回时将取消缓存
        if (parseInt(to.query._t) < parseInt(from.query._t)){  //表示是返回页面
            if(from.name === this.$options.name){  //如果是当前页面返回的话(this.$options.name是当前组件的名字)
                from.meta.myKeepAlive = false;
            }
        }
    },
},

当页面返回的时候设置它的myKeepAlive为false,为什么不是直接用from或者to,因为返回页面包括从上一个页面返回或者返回当前页面,from,to都可能不是当前出口的路由对象。

原理

// src/core/components/keep-alive.js

export default {
  name: 'keep-alive',
  abstract: true, // 判断此组件是否需要在渲染成真实DOM
  props: {
    include: patternTypes,
    exclude: patternTypes,
    max: [String, Number]
  },
  created() {
    this.cache = Object.create(null) // 创建对象来存储  缓存虚拟dom
    this.keys = [] // 创建数组来存储  缓存key
  },
  mounted() {
    // 实时监听include、exclude的变动
    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) { // 删除所有的缓存
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },
  render() {
      // 下面讲
  }
}

pruneCacheEntry函数

咱们上面实现的生命周期destroyed中,执行了删除所有缓存这个操作,而这个操作是通过调用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  // 设为null
  remove(keys, key) // 删除对应的元素
}
复制代码

总结一下就是做了三件事:

  • 1、遍历集合,执行所有缓存组件的$destroy方法
  • 2、将cache对应key的内容设置为null
  • 3、删除keys中对应的元素

js预加载

webpack代码分割技术

首先要分析大js的组成,然后看能拆分成多少个独立的js。再分析独立的JS之间的依赖关系,确定加载顺序。 如果你是用webpack相关的打包工具,它也是支持打包成多个文件的,配置就可以了。参考: 代码拆分是 webpack 最引人注目的特性之一。此功能允许您将代码拆分为各种捆绑包,然后可以按需或并行加载。它可用于实现更小的捆绑包并控制资源负载优先级,如果使用得当,将对加载时间产生重大影响。 有三种通用的代码拆分方法:

  • 入口点entry:使用配置手动拆分代码。
  • 防止重复:使用条目依赖项或SplitChunksPlugin重复数据删除和拆分块。
  • 动态导入:通过模块内的内联函数调用拆分代码。

预加载技术

juejin.cn/post/684490…

web缓存技术

http缓存

文件太大,通常预加载也是等不起的,通过浏览器缓存,这样用户再第一次请求之后,就会缓存下来,下次就从http缓存中读取了。参考 当一个用户发起一个静态资源请求的时候,浏览器会通过以下几步来获取资源:

  • 本地缓存阶段:先在本地查找该资源,如果有发现该资源,而且该资源还没有过期,就使用这一个资源,完全不会发送http请求到服务器;
  • 协商缓存阶段:如果在本地缓存找到对应的资源,但是不知道该资源是否过期或者已经过期,则发一个http请求到服务器,然后服务器判断这个请求,如果请求的资源在服务器上没有改动过,则返回304,让浏览器使用本地找到的那个资源;
  • 缓存失败阶段:当服务器发现请求的资源已经修改过,或者这是一个新的请求(在本来没有找到资源),服务器则返回该资源的数据,并且返回200, 当然这个是指找到资源的情况下,如果服务器上没有这个资源,则返回404。

服务器端缓存

CDN缓存

localStorage

构建可缓存站点的建议

来自alloyteam:如何构建可缓存站点

  • 同一个资源保证URL的稳定性
  • 给Css、js、图片等资源增加HTTP缓存头,并强制入口Html不被缓存
  • 减少对Cookie的依赖
  • 减少对HTTPS加密协议的使用
  • 多用Get方式请求动态Cgi
  • 动态CGI也是可以被缓存

缓存到indexedDB。每次从indexedDB中取出,瞬间加载