Vue h5项目性能优化

掘金上有很多大佬分享过性能优化的经验贴,但有一些方式针对需要快速的迭代的h5不太适用,这里分享一些适用于h5开发(Vue)性能优化的方法

vue 自带了模块分析 可以打包命令后添加--report 就会生成一个report.html 直接运行即可看到各个模块占比

一.加载优化

1.路由懒加载:

使用路由懒加载,不做路由懒加载的话,用户打开首页,会一次性加载所有资源

css 复制代码
{
    path: '/loading',
    name: 'loading',
    component: () => import('@/views/loading/index.vue'),
},

原理:依托ES6动态加载模import(),调用 import() 之处,被作为分离的模块起点,意思是,被请求的模块和它引用的所有子模块,会分离到一个单独的 chunk 中,可以通过魔法注释设置模块名称,名称相同的将会被组合到相同的块中

2.组件懒加载:

通过import 异步引入对应组件资源,但这样可能导致请求增多

拆分原则:

1.该页面体积过大,导致加载缓慢,通过浏览器并行发起请求,提示下载速度

2.该组件不是一进入页面就展示,需要一定条件下才触发(比如弹框组件)

3.该组件复用性高,很多页面都有引入,利用组件懒加载抽离出该组件,一方面可以很好利用缓存,同时也可以减少页面的 JS 文件大小(比如表格组件、图形组件等)

javascript 复制代码
// vue 中实现异步加载组件
import { reactive, ref, onMounted, computed, watch,defineAsyncComponent } from 'vue'
const rule = defineAsyncComponent(() => (import('_c/rule')))
3.Tree shaking 优化

export default 导出的是一个对象,无法知道里面是否使用未导出的对象,但通过export 导出的函数就能利用tree-shaking 去除代码中没有使用的部分

4.骨架屏

插件:vue-skeleton-webpack-plugin 可以给不同页面设置骨架屏

白屏时间调试:谷歌的Performance 中FP/FCP(首屏渲染)

5.长列表虚拟滚动

如果使用长图去进行列表滚动,所需要的渲染时间会很长,滚动时还会造成页面卡顿,整体体验非常不好

虚拟滚动------指的是只渲染可视区域的列表项,非可见区域的不渲染,在滚动时动态更新可视区域,该方案在优化大量数据渲染时效果是很明显的,目前已有成熟的虚拟滚动插件

6.使用requestAnimationFrame 制作动画

(1)引擎层面

setTimeout/setInterval 属于 JS引擎,requestAnimationFrame 属于 GUI引擎

JS引擎与GUI引擎是互斥的,也就是说 GUI 引擎在渲染时会阻塞 JS 引擎的计算

(2)时间是否准确

requestAnimationFrame 刷新频率是固定且准确的,但 setTimeout/setInterval 是宏任务,根据事件轮询机制,其他任务会阻塞或延迟js任务的执行,会出现定时器不准的情况

7. 调整JS 的加载方式

js 常用的有6种加载方式,async、defer 是 script 标签的专属属性,对于网页中的其他资源,可以通过 link 的 preload、prefetch 属性来预加载

xml 复制代码
1.正常加载:会阻塞 dom 渲染,浏览器必须等待 index.js 加载和执行完成后才能去做其它事情
<script src="index.js"></script>
​
​
2.异步加载:JS 不会阻塞 DOM 的渲染,async 加载是无顺序的,当它加载结束,JS 会立即执行
  使用场景:使用场景:若该 JS 资源与 DOM 元素没有依赖关系,也不会产生其他资源所需要的数据时,可以使用async 模式,比如埋点统计
<script async src="index.js"></script>
​
3.defer 模式:defer 资源会在 DOMContentLoaded 执行之前,并且 defer 是有顺序的加载,如果有多个设置了 defer 的 script 标签存在,则会按照引入的前后顺序执行,即便是后面的 script 资源先返回
    
 <script defer src="index.js"></script>
 
​
4.module 模式:在主流的现代浏览器中,script 标签的属性可以加上 type="module",浏览器会对其内部的 import 引用发起 HTTP 请求,获取模块内容。这时 script 的行为会像是 defer 一样,在后台下载,并且等待 DOM 解析
Vite 就是利用浏览器支持原生的 es module 模块,开发时跳过打包的过程,提升编译效率
​
<script type="module">import { a } from './a.js'</script>
​
5.preload:预加载,用于提前加载一些需要的依赖,这些资源会优先加载(如下图红框),vue2中 会自动给首页的所需资源添加预加载
    5.1preload 加载的资源是在浏览器渲染机制之前进行处理的,并且不会阻塞 onload 事件;
    5.2preload 加载的 JS 脚本其加载和执行的过程是分离的,即 preload 会预加载相应的脚本代码,待到需要时自行调用;
<link rel="preload" as="script" href="index.js">
​
6.prefetch:利用浏览器的空闲时间,加载页面将来可能用到的资源的一种机制
 prefetch 特点:
    6.1 prefetch 加载的资源可以获取非当前页面所需要的资源,并且将其放入缓存至少5分钟(无论资源是否可以缓存)
    6.2当页面跳转时,未完成的 prefetch 请求不会被中断
8.图片优化

1.图片动态裁剪:

利用阿里云/腾讯云cdn提供的图片动态裁剪功能,只需在图片的url地址上动态添加参数,就可以得到你所需要的尺寸大小,针对不同分辨率使用合适的图片可以有效减少图片尺寸。

ruby 复制代码
// 具体形式 h高度 w宽度 e(0:按长边缩放,1:按短边缩放) c(0:)

<https://oss-console-img-demo-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/example.jpg@100h_100w_1e_1c>

2.图片懒加载:

对于一些图片量比较大的首页,用户打开页面后,只需要呈现出在屏幕可视区域内的图片,当用户滑动页面时,再去加载出现在屏幕内的图片,以优化图片的加载效果

图片懒加载实现原理:

由于浏览器会自动对页面中的 img 标签的 src 属性发送请求并下载图片,可以通过 html5 自定义属性 data-xxx 先暂存 src 的值,然后在图片出现在屏幕可视区域的时候,再将 data-xxx 的值重新赋值到 img 的 src 属性即可

二、图片渲染优化

css 复制代码
1.CSS写在头部,JS写在尾部并异步
​
2.避免img、iframe等的src为空:空src会重新加载当前页面,影响速度和效率
​
3.尽量避免重置图像大小:多次重置图像大小会引发图像的多次重绘,影响性能
​
4.大图像尽量避免使用DataURL:DataURL图像没有使用图像的压缩算法,文件会变大,并且要解码后再渲染,加载慢耗时长

三、dom渲染优化

css 复制代码
1.减少dom节点
​
2.优化动画
    1.尽量使用CSS3动画
    2.合理使用requestAnimationFrame动画代替setTimeout
    
3.GPU加速
    使用某些HTML5标签和CSS3属性会触发GPU渲染
    1.css 属性opacity、transform、transition
    2.HTML标签 video、canvas、webgl

四.样式优化

arduino 复制代码
1.避免在HTML中书写style
​
2.避免CSS表达式,CSS表达式的执行需跳出CSS树的渲染
​
3.正确使用display
    display:inline后不应该再使用float、margin、padding、width和height
    display:inline-block后不应该再使用float
    display:block后不应该再使用vertical-align
    display:table-*后不应该再使用float和margin
 
4.不声明过多的font-size
​
5.值为0时不需要任何单位

五.脚本优化

arduino 复制代码
1.减少重绘和回流
    避免不必要的DOM操作
    避免使用document.write
    减少drawImage
    尽量改变class而不是style,使用classList代替className
    用DOMFragment缓存批量化DOM操作
 
2.尽量避免操作Dom,可以先用
​
3.缓存.length的值:每次.length计算用一个变量保存值

六.构建优化

基于各类打包工具进行体积优化,

减少打包时间:缩减范围缓存副本定向搜索提前构建并行构建可视结构

减少打包体积:分割代码摇树优化动态垫片按需加载作用提升压缩资源

1.减少打包时间
javascript 复制代码
​
1.配置include/exclude 
    减少检索的范围,一般是再各loader中进行配置
export default {
    // ...
    module: {
        rules: [{
            exclude: /node_modules/,
            include: /src/,
            test: /.js$/,
            use: "babel-loader"
        }]
    }
};
​
​
2.缓存副本
  配置cache缓存Loader对文件的编译副本,大部分Loader/Plugin都会提供一个可使用编译缓存的选项,通常包含cache字眼。以babel-loader
export default {
    module: {
        rules: [{
            // ...
            test: /.js$/,
            use: [{
                loader: "babel-loader",
                options: { cacheDirectory: true }
            }]
        }]
    },
};
​
3.定向搜索
    配置resolve提高文件的搜索速度
export default {
    // ...
    resolve: {
        alias: {
            "#": '', // 根目录快捷方式
            "@": '', // src目录快捷方式
            swiper: "swiper/js/swiper.min.js"
        }, 
        // 模块导入快捷方式
        extensions: [".js", ".ts", ".jsx", ".tsx", ".json", ".vue"] // import路径时文件可省略后缀名
    }
};
​
4.并行构建
    配置Thread将Loader单进程转换为多进程,若项目文件不算多就不要使用,开启多个线程也会存在性能开销。
​
​
5.可视结构,寻找体积过大的包
import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
​
export default {
    // ...
    plugins: [
        // ...
        BundleAnalyzerPlugin()
    ]
};
2.减少打包体积
javascript 复制代码
1.分割代码
    webpack v4使用splitChunks替代CommonsChunksPlugin实现代码分割。
​
​
2.摇树
    删除项目中未被引用代码,只对ESM模块有效,webpack中将模式设置为production就可以开启摇树
    
3.动态垫片
    通过垫片服务根据UA返回当前浏览器代码垫片,好处是无需将繁重的代码垫片打包进去
    
​
4.按需加载
    webpack中配合import()实现按需加载
    // 魔术注解
    const Login = () => import( /* webpackChunkName: "login" */ "../../views/login");
    const Logon = () => import( /* webpackChunkName: "logon" */ "../../views/logon");
3.抽离第三方包
arduino 复制代码
configureWebpack: config => {
    // 再这里配置不需要进行打包的组件
    config.externals = {
      vant: 'vant',
      axios: 'axios',
    }
  },
4.开启gzip压缩

一般正式项目上了cdn后 自动开启gzip压缩模式,所以一般无需配置,如果有需要的话,可以开启(需要nginx 也配置相关的) 默认nginx是可以直接转换压缩的,只不过直接有gz文件可以省去压缩的时间

javascript 复制代码
// 开启gzip压缩
const CompressionPlugin = require('compression-webpack-plugin')
​
// vue.config.js
config.plugins.push(
      new CompressionPlugin({
        filename: '[path].gz[query]',
        test: /.js$|.css$|.html$|.ttf$|.eot$|.woff$/, // 匹配文件名
        threshold: 10240, // 对超过10k的数据压缩
        deleteOriginalAssets: false, // 不删除源文件
      })
    )
5.分包 splitChunks

项目中的第三方库默认会被打包到一个文件名含vendors的bundle中,splitChunks可以抽离出常用的第三方包,不整合到主包中

yaml 复制代码
// 分离第三方包
    config.optimization = {
      splitChunks: {
        chunks: 'all',
        // 入口和它的同步依赖最多能被拆分的数量,默认为3
        maxInitialRequests:5,
        cacheGroups: {
          axios: {
            name: 'axios',
            test: /[\/]node_modules[\/]axios[\/]/,
            priority: -10,
          },
          vant: {
            name: 'vant',
            test: /[\/]node_modules[\/]vant[\/]/,
            priority: -10,
          },
          'vue-router': {
            name: 'vue-router',
            test: /[\/]node_modules[\/]vue-router[\/]/,
            priority: -10,
          },
          pinia: {
            name: 'pinia',
            test: /[\/]node_modules[\/]pinia[\/]/,
            priority: -10,
          },
        },
      },
    }
相关推荐
匹马夕阳2 小时前
Vue 3中导航守卫(Navigation Guard)结合Axios实现token认证机制
前端·javascript·vue.js
你熬夜了吗?2 小时前
日历热力图,月度数据可视化图表(日活跃图、格子图)vue组件
前端·vue.js·信息可视化
沈梦研9 小时前
【Vscode】Vscode不能执行vue脚本的原因及解决方法
ide·vue.js·vscode
轻口味10 小时前
Vue.js 组件之间的通信模式
vue.js
fmdpenny12 小时前
Vue3初学之商品的增,删,改功能
开发语言·javascript·vue.js
涔溪13 小时前
有哪些常见的 Vue 错误?
前端·javascript·vue.js
亦黑迷失15 小时前
vue 项目优化之函数式组件
前端·vue.js·性能优化
计算机-秋大田15 小时前
基于SpringBoot的高校教师科研的设计与实现(源码+SQL脚本+LW+部署讲解等)
java·vue.js·spring boot·后端·课程设计
eason_fan15 小时前
分析vue3源码23(异步组件实现)
vue.js·前端框架·源码阅读
BigData-018 小时前
vue视频流播放,支持多种视频格式,如rmvb、mkv
前端·javascript·vue.js