前端性能优化,Vue或Webpack项目集成 Service Worker 开启离线缓存

前端资源加载和性能优化一直是个令人头疼的问题,下面是我开发这些年的一些优化总结。

资源加载优化,从两个方面优化:减少项目服务器带宽压力、减少用户加载资源体
1、打包时压缩js、css、媒体等资源文件
2、部分js和css可改换成CDN服务器资源,使用CDN服务加载资源可以减轻项目服务器带宽压力,项目服务器带宽不足时优化效果非常明显,切记不可盲目把资源更换为CDN资源,大部分第三方依赖在使用时是按需加载的,如果使用直接使用CDN引入,则会加载所有代码,当用户端网络不佳时,会影响用户使用体验。
例如 Element-UI,如果你大量使用了其中的组卷,则可以使用CDN引入。如果仅仅使用了其中几个组件,则可以按需加载把 Element-UI 打包到项目中。目的是使用户查看网站时,加载的资源尽可能的少。
3、部分插件的js或css只在个别页面用到,可以考虑异步加载这些资源,并对href进行判断,哪些页面使用了此资源就切换为同步加载,防止刷新页面报错。
4、使用 Service Worker 对项目静态资源进行离线加载,用户第二次进入页面直接从本地读取资源,速度飞快。
代码层面优化
1、除首页外,其它vue页面和组件尽量使用懒加载方式引入。
2、小图标打包成base64到项目js文件中,减少网络请求次数,如果图标多处使用记得放到公共css文件中,减少打包后的项目体量。
3、首页引用的方法尽量放到一起,避免加载很多js小文件。
4、代码、组件能复用的,在不影响项目可读性的情况向,尽量提取成为公共方法、组件,减少项目体积。
5、防抖可节流,防止方法频繁触发。
其它方面优化
1、升级服务器 HTTP/2,提升接口请求速度。
2、有些接口数据不经常变动,可以考虑缓存到本地,避免重复请求,提高页面响应速度。
接下来要说的就是要重点,离线缓存,可以极大提升用户使用体验
离线缓存我最开始接触到的是 manifest 方案,使用的时候需要配置缓存文件清单,在html页面引入即可,当时我还用node写过一个自动生成清单文件的脚本,不过现在这个方案已经被放弃了。
目前的离线缓存方案是通过 service worker 使用 fatch 拦截全局请求并给出自己的响应,这给了完全控制项目文件的可能。包括预加载,按需加载,离线缓存,主动更新。

根据这些特性,我写了一个webpack plugin,直接把 Service Worker 离线缓存及更新功能集成到项目中。使用请查看文档
generate-service-worker-webpack-plugin – npm (npmjs.com)

接下来是重点了,讲讲离线缓存更新。

当我们使用 Service Worker 之后,用户打开浏览器进入页面,sw服务将一直在后台挂起,强制刷新不会关闭sw服务,关闭页面或浏览器,再次进入页面sw服务将自动运行。这就导致一个非常严重的问题,即应用更新,如果盲目的使用了 Service Worker 开启缓存,那么后面即使服务端去掉了这部分代码,用户端sw也在运行,需要用户进入控制台进行关闭和清除,这将导致非常严重的后果。所以在开启 Service Worker 服务之前,一定要有结束 sw 服务的控制逻辑,方便后续更新。

接下来讲讲我使用 Service Worker 开启离线缓存并更新的思路,还有项目如果去掉打算停用Service Worker,不再进行离线缓存,用户端关闭sw服务的方式。

在使用 generate-service-worker-webpack-plugin,打包之后 sw.js、sw.hash、index.html 中都会保存有一个相同的 hash 值

触发检查更新方式有两种

1、由index.html触发。如果服务端项目弃用了此插件,新加载的index.html会无法触发,此时由sw.js控制。
2、由sw.js触发。拦截 fetch 时判断并检查更新,为防止重复检查更新会有一定的限制处理。

a、进入页面 index.html 先发送 postMessage 到 sw.js,sw.js 收到 message 立即触发检查更新,并刷新有效时间;(有效时间内不会再次检查更新)
b、若 sw.js 未收到 message,则在发生 fetch 请求时判断 clientId 是否变动,如果变动则触发检查更新,并刷新有效时间;(用户每次刷新窗口,clientId 都会改变)

判断是否更新

1、请求 sw.hash 比较返回结果与当前 sw.js 中的是否相同
    相同:向页面发起 postMessage,页面接收把当前页面的 hash 发送回 sw.js,再比较 hash 是否相同,
        如果相同,则离线缓存为最新版本,可用。
        如果不同则立即清除缓存并注销 sw.js;
        如果向页面发起 postMessage,页面在500ms内没有响应 sw.js,可能用户已弃用 sw.js,立即清除缓存并注销 sw.js;
        不同:说明项目已经更新,清除所有缓存,注销 sw.js,刷新页面;

2、如果 请求 sw.hash 失败
    判断用户端网络是否正常,
    如果网络正常,则说明此项目可能已经放弃使用 sw.js,立即清除缓存并注销 sw.js;
    如果网络断开连接,则直接使用离线缓存即可;

这样就解决了停用 Service Worker 和应用更新的问题,项目源码放到github上了,使用有什么问题可以找我交。

blcyzycc/generate-service-worker-webpack-plugin: webpack打包自动生成并添加 service worker 文件的插件 (github.com)

目前已经在公司项目多次使用,一切正常,更新ok,通过上面那些优化方式,成功把公司一个老项目优化到秒开,原来需要五六秒。

大家如果想体验 Service Worker 带来的离线优化,可以先试试我这个。

原文链接:https://juejin.cn/post/7214349925065310266 作者:用户654272220723

(2)
上一篇 2023年3月26日 上午10:16
下一篇 2023年3月26日 上午10:26

相关推荐

发表回复

登录后才能评论