首页 > 其他分享 >前端项目首页加载速度及项目性能优化

前端项目首页加载速度及项目性能优化

时间:2023-04-04 14:58:41浏览次数:40  
标签:vue 项目 JS js 首页 组件 加载 页面

提升首屏的加载速度或项目整体优化,是前端性能优化中最重要的环节,接下来跟大家分享一些常规且有效的首屏优化建议及做法。

一、路由懒加载

SPA项目,一个路由对应一个页面,如果不做处理,项目打包后,会把所有页面打包成一个文件,当用户打开首页时,会一次性加载所有的资源,造成首页加载很慢,降低用户体验,因此,我们需要将;路由全部改成懒加载,提高加载速度。

// 通过webpackChunkName设置分割后代码块的名字
const Home = () => import(/* webpackChunkName: "home" */ "@/views/home/index.vue")
const About = () => import(/* webpackChunkName: "about" */ "@/views/about/index.vue")

const routes = [
  {
    path: "/",
    name: "home",
    component: Home
  },
  {
    path: "/about",
    name: "about",
    component: About
  }
]

重新打包后,首页资源拆分为app.js和home.js,以及对应的css文件

  • app.js:244KB、home.js:35KB

  • app.css:67KB、home.css:15KB

二、组件懒加载

除了路由的懒加载外,组件的懒加载在很多场景下也有重要的作用,比如:home页面和about页面都引入了dialogInfo弹框组件,该弹框不是已进入页面就加载,而是需要用户手动触发后才展示出来,那么在这种场景下,就很适合用懒加载的方式引入。

// 弹框组件懒加载
<script>
const dialogInfo = () => import(/* webpackChunkName: "dialog" */ "@/components/dialogInfo")
export default {
  name: "home",
  components: {
    dialogInfo
  }
}
</script>

重新打包后,dist打包中的home.js和about.js中没有了弹框组件的代码,该组件被独立打包成dialogInfo.js,当用户点击触发后才会去加载dialogInfo.js和dialogInfo.css。

组件懒加载的使用场景:

有时对于资源的拆分过细也不高,可能会造成浏览器http请求的增多,以下三种适合组件懒加载的场景:

  1. 该页面的JS文件体积大,导致页面打开慢,可以通过组件懒加载进行资源拆分,利用浏览器并行下载资源,提升下载速度(比如首页)
  2. 该组件不是已进入页面就展示,需要一定条件下才触发(比如弹框组件)
  3. 该组件复用性高,很多页面都有引入,利用组件懒加载抽离出该组件,一方面可以很好利用缓存,同时也可以减少页面的JS文件大小(比如表格组件、图形组件等)

三、合理使用Tree shaking

Tree shaking的作用:消除无用的JS代码,减少代码体积。

// util.js
export function targetType(target){
  return Object.prototype.toString.call(target).slice(8,-1).toLowerCase();
}
export function deepClone(target){
  return JSON.parse(JSON.stringify(target))
}

假如项目中只使用了targetType方法,但未使用deepClone方法,项目打包后,deepClone方法不会被打包到项目里。

Tree shaking的原理:依赖于ES6的模块特性,ES6模块依赖关系是确定的,和运行时的状态无关,可以进行可靠的静态分析,这就是Tree shaking的基础。静态分析就是不需要执行代码,就可以从字面量上对代码进行分析。ES6之前的模块化,比如CommonJS是动态加载,只有执行后才知道引用的什么模块,就不能通过静态分析去做优化,正是基于这个基础上,才使得Tree shaking成为可能。

Tree shaking并不是万能的:并不是说所有无用的代码都可以被消除,还是上面的代码,换个写法Tree shaking就失效了。

// util.js
export default {
  targetType(target){
    return Object.prototype.toString.call(target).slice(8,-1).toLowerCase();
  },
  deepClone(target){
    return JSON.parse(JSON.stringify(target));
  }
}

//引入并使用
import util from '../util'
util.targetType(null)

同样的,假如项目中只使用了targetType方法,未使用deepClone方法,项目打包后,deepClone方法还是会被打包到项目里。究其原因,export default导出的是一个对象,无法通过静态分析判断出一个对象的哪些变量未被使用,所以Tree shaking只对使用export导出的变量生效。

这也是函数式编程越来越受欢迎的原因,因为可以很好利用Tree shaking精简项目的体积,也是Vue3全面拥抱了函数式编程的原因之一。

四、骨架屏优化白屏时长

使用骨架屏可以缩短白屏时间,提升用户体验,国内大多数主流网站都使用了骨架屏,特别是手机端的项目。SPA单页应用,最初的html都是空白的,需要通过加载JS讲内容挂载到根节点上,这套机制的副作用:会造成长时间的白屏。

常见的骨架屏插件就是基于这种原理,在项目打包时将骨架屏的内容直接放到html文件的根节点中,使用骨架屏插件,打包后的html文件(根节点内部为骨架屏):  

同一项目,对比使用骨架屏前后的FP(白屏时间):

  • 无骨架屏:白屏时间1063ms

  • 有骨架屏:白屏时间144ms

骨架屏确实是优化白屏的不二选择,这里推荐大家使用:vue-skeleton-webpack-plugin,该插件的亮点是可以给不同的页面设置不同的骨架屏。

// 安装
npm i vue-skeleton-webpack-plugin

// vue.config.js配置
const SkeletonWebpackPlugin = require("vue-skeleton-webpack-plugin")
module.exports = {
  configureWebpack: {
     plugins: [
         new SkeletonWebpackPlugin({
            // 实例化插件对象
            webpackConfig: {
               entry: {
                  app: path.join(__dirname, './src/skeleton.js') // 引入骨架屏入口文件
               }
            },
            minimize: true, // SPA 下是否需要压缩注入 HTML 的 JS 代码
            quiet: true, // 在服务端渲染时是否需要输出信息到控制台
            router: {
               mode: 'hash', // 路由模式
               routes: [
                  // 不同页面可以配置不同骨架屏
                  // 对应路径所需要的骨架屏组件id,id的定义在入口文件内
                  { path: /^\/home(?:\/)?/i, skeletonId: 'homeSkeleton' },
                  { path: /^\/detail(?:\/)?/i, skeletonId: 'detailSkeleton' }
               ]
            }
        })
      ]
   }
}

// skeleton.js文件
import Vue from "vue"
// 引入对应的骨架屏页面
import homeSkeleton from "./views/homeSkeleton";
import detailSkeleton from "./views/detailSkeleton";

export default new Vue({
    components: {
        homeSkeleton,
        detailSkeleton,
    },
    template: `
    <div>
      <homeSkeleton id="homeSkeleton" style="display:none;" />
      <detailSkeleton id="detailSkeleton" style="display:none;" />
    </div>
  `,
});

五、长列表虚拟滚动

项目中不乏有需要渲染长列表的场景,当渲染条数过多时,所需要的渲染时间会很长,滚动时还会造成页面卡顿,整体体验非常不好。

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

虚拟滚动的插件有很多,这里推荐大家使用:vue-virtual-scroller,该插件主要有RecycleScroller.vue、DynamicScroller.vue这两个组件,其中RecycleScroller需要item的高度为静态的,也就是列表每个item的高度都是一致的,而DynamicScroller可以兼容item的高度为动态的情况。

// 安装插件
npm install vue-virtual-scroller

// main.js
import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'

Vue.use(VueVirtualScroller)

// 使用
<template>
  <RecycleScroller
    class="scroller"
    :items="list"
    :item-size="32"
    key-field="id"
    v-slot="{ item }">
      <div class="user"> {{ item.name }} </div>
  </RecycleScroller>
</template>

六、Web Worker优化长任务

由于浏览器GUI渲染线程与JS引擎线程是互斥的关系,当页面中有很多长任务时,会造成页面UI阻塞,出现界面卡顿、掉帧等情况。

查看页面的长任务:打开控制台,选择Performance工具,点击Start按钮,展开Main选项,会发现有很多红色的三角,这些就属于长任务(长任务:执行时间超过50ms的任务)

 

 

 如果直接把下面这段代码丢到主线程中,计算过程中页面会一直处于卡死状态,无法操作。

let sum = 0;
for (let i = 0; i < 200000; i++) {
    for (let i = 0; i < 10000; i++) {
      sum += Math.random()
    }
}

使用Web Worker执行上述代码时,计算过程中页面正常可操作、无卡顿。

// worker.js
onmessage = function (e) {
  // onmessage获取传入的初始值
  let sum = e.data;
  for (let i = 0; i < 200000; i++) {
    for (let i = 0; i < 10000; i++) {
         sum += Math.random()
      }
  }
  // 将计算的结果传递出去
   postMessage(sum);
}

Web Worker的通信时长:并不是执行时间超过50ms的任务,就可以使用Web Worker,还要考虑通信时长的问题。

假如一个运算执行时长为100ms,但是通信时长为300ms,用了Web Worker可能会更慢,比如新建一个Web Worker,浏览器会加载对应的worker.js资源,下图中的Time是这个资源的通信时长(也叫加载时长)

当任务的运算时长 - 通信时长 > 50ms,推荐使用Web Worker。

七、requestAnimationFrame制作动画

requestAnimationFrame是浏览器专门为动画提供的API,它的刷新频率与显示器的频率保持一致,使用该API可以解决用setTimeout/setInterval制作动画卡顿的情况。

八、JS的6种加载方式

1、正常模式

<script src="index.js"></script>

这种情况下JS会阻塞dom渲染,浏览器必须等待index.js加载和执行完成后才能去做其它事情。

2、async模式

<script async src="index.js"></script>

async模式下,它的加载是异步的,JS不会阻塞dom的渲染,async加载是无顺序的,当它加载结束,JS会立即执行。

使用场景:若该JS资源与dom元素没有依赖关系,也不会产生其他资源所需要的数据时,可以使用async模式,比如:埋点统计。

3、defer模式

<script defer src="index.js"></script>

defer模式下,JS的加载也是异步的,defer资源会在DOMContentLoaded执行之前,并且defer是有顺序的加载,如果有多个设置了defer的script标签存在,则会按照引入的前后顺序执行,即便是后面的script资源先返回,所以defer可以用来控制JS文件的执行顺序,比如:element-ui.js和vue.js,因为element-ui.js依赖于vue,所以必须先引入vue.js,再引入element-ui.js。

<script defer src="vue.js"></script>
<script defer src="element-ui.js"></script>

使用场景:一般情况下都可以使用defer,特别是需要控制资源加载顺序时。

4、module模式

<script type="module">import { a } from './a.js'</script>

在主流的现代浏览器中,script标签的属性可以加上type="module",浏览器会对其内部的import引用发起http请求,获取模块内容。这时的script的行为会像是defer一样,在后台下载,并且等待dom解析。

Vite就是利用浏览器支持原生的es module模块,开发时跳过打包的过程,提升编译效率。

5、preload

<link rel="preload" as="script" href="index.js"></link>

link标签的preload属性:用于提前加载一些需要的依赖,这些资源会优先加载。

特点:加载的资源是在浏览器渲染机制之前进行处理的,并且不会阻塞onload事件;加载的JS脚本其加载和执行的过程是分离的,即preload会预加载相应的脚本代码,待到需要时自行调用。

6、prefetch

<link rel="prefetch" as="script" href="index.js"></link>

prefetch是利用浏览器的空闲时间,加载页面将来可能用到的资源的一种机制;通常可以用于加载其他页面(非首页)所需要的资源,以便加快后续页面的打开速度。

特点:加载的资源可以获取非当前页面所需要的资源,并且将其放入缓存至少5分钟(无论资源是否可以缓存);当页面跳转时,未完成的prefetch请求不会被中断。

加载方式总结:

async、defer是script标签的专属属性,对于网页中的其他资源,可以通过link的preload、prefetch属性来预加载;如今现代框架已经将preload、prefetch添加到打包流程中了,通过灵活的配置,去使用这些预加载功能,同时我们也可以审时度势地向script标签添加async、defer属性去处理资源,这样可以显著提升性能。

九、图片的优化

大部分性能优化工作都集中在JS方面,但图片也是页面上非常重要的部分,特别是对于移动端来说,完全没有必要去加载原图,浪费带宽。如何去压缩图片,让图片更快的展示出来,有很多优化工作可以做。

1、图片的动态裁剪

很多云服务,比如阿里云或七牛云,都提供了图片的动态裁剪功能,效果很棒,只需在图片的url地址上动态添加参数,就可以得到你所需要的尺寸大小,比如:http://7xkv1q.com1.z0.glb.clouddn.com/grape.jpg?imageView2/1/w/200/h/200,图片也从原来的1.8MB变为12.8KB。

2、图片懒加载

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

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

这里推荐大家使用:vue-lazyload

// 安装
npm install vue-lazyload

// main.js 注册
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// 配置项
Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'dist/error.png', // 图片加载失败时的占位图
  loading: 'dist/loading.gif', // 图片加载中时的占位图
  attempt: 1
})

// 通过 v-lazy 指令使用
<ul>
    <li v-for="img in list">
        <img v-lazy="img.src" :key="img.src" >
    </li>
</ul>

3、使用字体图标

字体图标是页面使用小图标的不二选择,最常用的就是iconfont。

优点:轻量级,一个图标字体要比一系列的图像要小。一旦字体加载了,图标就会马上渲染出来,减少了http请求;灵活性,可以随意改变颜色、阴影、透明效果、旋转等;兼容性,几乎支持所有的浏览器,可放心使用。

4、图片base64格式

将小图片转换为base64编码字符串,并写入html或者css中,减少http请求。

优缺点:处理的往往是非常小的图片,因为base64编码后,图片大小会膨胀为原文件的4/3,如果对大图也使用base64编码,后者的体积会明显增加,即便减少了http请求,也无法弥补这庞大的体积带来的性能开销,得不偿失;在传输非常小的图片的时候,base64带来的文件体积膨胀,以及浏览器解析base64的时间开销,与它节省掉的htto请求开销相比,可以忽略不计,这时候才能真正体现出它在性能方面的优势。

项目可以使用url-loader将图片转base64

// 安装
npm i url-loader --save-dev

// 配置
module.exports = {
  module: {
    rules: [{
      test: /.(png|jpg|gif)$/i,
         use: [{
        loader: 'url-loader',
            options: {
          // 小于 10kb 的图片转化为 base64
               limit: 1024 * 10
             }
      }]
    }]
  }
};

优化总结:

虽然以上都是一些常规方案,但其中可以深挖的知识点并不少,经过上面的一系列优化,首页打开的速度及项目的性能应该都有了明显的提升。

标签:vue,项目,JS,js,首页,组件,加载,页面
From: https://www.cnblogs.com/coolsboy/p/17286392.html

相关文章

  • 前端项目首页加载速度及项目性能优化
    提升首屏的加载速度或项目整体优化,是前端性能优化中最重要的环节,接下来跟大家分享一些常规且有效的首屏优化建议及做法。一、路由懒加载SPA项目,一个路由对应一个页面,如果不做处理,项目打包后,会把所有页面打包成一个文件,当用户打开首页时,会一次性加载所有的资源,造成首页加载很慢,降......
  • app直播源码,css预加载旋转动画 与 流光字体
    app直播源码,css预加载旋转动画与流光字体一、预加载旋转动画Html<viewclass="concentric_round"></view>​cssbody{}.concentric_round{width:200rpx;height:200rpx;position:relative;position:absolute;top:50%;left:50%;transform:translate(-50%,-100%);}.......
  • 创建SpringSecurity项目
    一.搭建SpringBoot开发环境我们的SpringSecurity系列教程会基于SpringBoot环境,并且以案例迭代的方式进行开发,所以为了方便后续案例的编写,我们先提前搭建一个SpringBoot环境的Web项目。1.创建SpringBoot项目如各位对SpringBoot基础不熟悉,请参考本人的SpringBoot系列教程:blo......
  • Tomcat 应用中并行流带来的类加载问题
    vivo互联网技术微信公众号 作者:肖铭轩、王道环随着Java8的不断流行,越来越多的开发人员使用并行流(parallel)这一特性提升代码执行效率。但是,作者发现在Tomcat容器中使用并行流会出现动态加载类失败的情况,通过对比Tomcat多个版本的源码,结合并行流和JVM类加载机制的原理,成......
  • 一个简单的rust项目贪吃蛇
    一个贪吃蛇游戏的rust实现,使用了piston_window和randcrate。游戏使用上下左右方向键进行操控,使用R重置游戏,使用P进行暂停/启动。项目结构·├──Cargo.lock├──Cargo.toml├──src/│  ├──main.rs│  ├──snake_game/│  │ ├─......
  • SpringBoot之使用IDEA新建Web项目
    1.打开IDEA,点击左上角的File选项,打开菜单选择New,再打开菜单选择Project2.选择SpringInitializr,输入或选择项目相关的信息3.选择SpringBoot版本以及相应的依赖,并点击右下角的Create按钮进行项目创建4.项目创建完成后,点击左上角的File选项,打开菜单选择Settings选......
  • Excel 如何计算项目完成时间占全年百分比 - 小技巧
    一、新建“项目记录表”数据表,含有“项目名称”、“开始时间”及“结束时间”等信息,我们现在需要计算出项目所需要的时间占全年的百分比。如图所示二、单击选中“结束时间”右边的单元格并输入“占全年时间的百分比”,然后按住鼠标左键往下拉到表格底部。选中该列,如图所示:三......
  • VSCode打开Vue项目
    打开VSCode                                                                       打开文件夹并选择vue的文件夹  ......
  • 信息系统项目管理师第四版知识摘编:第17章 项目干系人管理​
    第17章项目干系人管理项目干系人管理包括识别能够影响项目或会受项目影响的人员、团体或组织,分析干系人对项目的期望和影响,制定管理策略有效调动干系人参与项目决策和执行。17.1管理基础17.1.1管理的重要性每个项目都有干系人,他们会受到项目积极或消极的影响,或者能对项目施加积极......
  • Java使用IntelliJ IDEA配置Maven并管理一个webapp项目
    1、下载并安装Mavenapache官网地址:http://maven.apache.org/download.cgips:maven的使用是基于JDK的,所以电脑必须有JDK解压到文件夹,并配置环境变量。1、MAVEN_HOME,地址为maven的地址2、path,地址为%MAVEN_HOME%\binwin+r输入cmd进终端,输入mvn-v测试maven是否安装成功修改maven......