当前位置: 首页 > news >正文

前端项目的通用优化策略

一、虚拟滚动

当我们开发的时候,遇到大数据加载,页面卡顿的问题应该如何处理?大多数情况下,我们都是尽量通过分页的方式处理这类问题,但是总有一些特殊的情况我们必须把数据全部加载到前端进行处理。我曾经遇到过一个坑爹的组件,必须一次性加载几万条数据到页面上,导致一打开这个组件,就会让页面疯狂卡顿,当时便用了虚拟滚动解决了这个棘手的问题。

所以当我们遇到这种情况:渲染长列表的场景,当渲染条数过多时,所需要的渲染时间会很长,滚动时还会造成页面卡顿,整体体验非常不好。完全可以考虑使用虚拟滚动这个解决方案。

虚拟滚动——指的是只渲染可视区域的列表项,非可见区域的不渲染,在滚动时动态更新可视区域,该方案在优化大量数据渲染时效果是很明显的。以下这个图较为清晰地解释了虚拟滚动的工作原理。
在这里插入图片描述
虚拟滚动基本原理:

计算出 totalHeight 列表总高度,并在触发时滚动事件时根据 scrollTop 值不断更新 startIndex 以及 endIndex ,以此从列表数据 listData 中截取对应元素。

虚拟滚动插件

虚拟滚动的使用场景不少,网上有很多已经造好的轮子,我们也可以适当地选择更快更便捷的方式解决我们的页面问题。

虚拟滚动的插件有很多,比如 vue-virtual-scroller、vue-virtual-scroll-list、react-tiny-virtual-list、react-virtualized 等

这里简单介绍 vue-virtual-scroller 的使用

// 安装插件
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>

该插件主要有 RecycleScroller.vue、DynamicScroller.vue 这两个组件,其中 RecycleScroller 需要 item 的高度为静态的,也就是列表每个 item 的高度都是一致的,而 DynamicScroller 可以兼容 item 的高度为动态的情况

二、Web Worker 优化长任务

浏览器对页面的渲染时单线程的,导致我们的页面无法同时渲染CSS和JS代码。所以由于浏览器 GUI 渲染线程与 JS 引擎线程是互斥的关系,当页面中有很多长任务时,会造成页面 UI 阻塞,出现界面卡顿、掉帧等情况。

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

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 的通信时长

当然Web Worker我们也不能滥用,毕竟加载worker也是需要消耗一定的服务器资源。并不是执行时间超过 50ms 的任务,就可以使用 Web Worker,还要先考虑通信时长的问题假如一个运算执行时长为 100ms,但是通信时长为 300ms, 用了 Web Worker可能会更慢
比如新建一个 web worker, 浏览器会加载对应的 worker.js 资源,下图中的 Time 是这个资源的通信时长(也叫加载时长)。

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

三、requestAnimationFrame 制作动画

页面如果想要更加吸人眼球,动画必不可少。但是动画有时候会让页面看起来卡顿,而且也比较消耗浏览器的资源。那么为了解决这样的一些问题,我们可以使用requestAnimationFrame这个API来处理我们的动画效果。

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

①引擎层面
setTimeout/setInterval 属于 JS引擎,requestAnimationFrame 属于 GUI引擎JS引擎与GUI引擎是互斥的,也就是说 GUI 引擎在渲染时会阻塞 JS 引擎的计算。

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

③性能层面
当页面被隐藏或最小化时,setTimeout/setInterval 定时器仍会在后台执行动画任务,而使用 requestAnimationFrame 当页面处于未激活的状态下,屏幕刷新任务会被系统暂停。

四、JS的加载方式

关于我们页面的加载,相信很多人都知道在单线程的加载方式下,很多时候错误的编码会导致页面的阻塞,从而影响用户的体验,那么关于这点,我们应该更详细地去了解JS的加载方式。

①正常模式

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

这种情况下 JS 会阻塞 dom 渲染,浏览器必须等待 index.js 加载和执行完成后才能去做其它事情。也就是说如果整个页面跑下来,遇到这行代码将会直接停止页面dom的渲染,等到js文件加载完毕后,才能够再去绘制页面。

②async 模式

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

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

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

③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。

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

④module 模式

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

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

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

⑤preload 模式

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

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

1)preload 加载的资源是在浏览器渲染机制之前进行处理的,并且不会阻塞 onload 事件;

2)preload 加载的 JS 脚本其加载和执行的过程是分离的,即 preload 会预加载相应的脚本代码,待到需要时自行调用;

⑥prefetch 模式

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

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

prefetch 特点:

1)pretch 加载的资源可以获取非当前页面所需要的资源,并且将其放入缓存至少5分钟(无论资源是否可以缓存)

2)当页面跳转时,未完成的 prefetch 请求不会被中断

加载方式的总结

async、defer 是 script 标签的专属属性,对于网页中的其他资源,可以通过 link 的 preload、prefetch 属性来预加载。

如今现代框架已经将 preload、prefetch 添加到打包流程中了,通过灵活的配置,去使用这些预加载功能,同时我们也可以审时度势地向 script 标签添加 async、defer 属性去处理资源,这样可以显著提升性能。 所以通常情况下,当我们使用了打包工具时,也不需要我们去管理太多复杂的加载形式,只需要通过简单的配置即可达到我们想要的效果。

http://www.lryc.cn/news/66048.html

相关文章:

  • 关于 IO、存储、硬盘和文件系统
  • 计算机网络期中复习提纲-酷酷的聪整理版
  • clickhouse的嵌套数据结构Tuple、Array与Nested类型介绍和使用示例
  • 人脸修复增强调研
  • 【Java】继承和多态
  • ThingsBoard集群部署之k8s
  • 【Gorm】如何在 GORM 中实现模型之间的关联?
  • Linux危险命令
  • FPGA入门系列13--异步串口通信
  • k8s基础4——deployment控制器、应用部署、升级、回滚、水平扩容缩容
  • 动态规划算法——40道leetcode实例入门到熟练
  • Nmap入门到高级【第十一章】
  • 配置本地Angular环境并使用VsCode调试Angular前端项目
  • 100ASK_全志V853-PRO开发板支持人形检测和人脸识别
  • 简单实现基于UDP与TCP的回显服务器
  • 家用洗地机有什么推荐的吗?家用洗地机哪款好
  • 深度学习与文本聚类:一篇全面的介绍与实践指南
  • AP5153 线性降压恒流驱动芯片 2.5A
  • Unity物理系统脚本编程(下)
  • 容器技术的发展
  • Python Flask request中常见存储参数的介绍
  • php+vue网盘系统的设计与实现
  • [前端]深浅拷贝
  • 文章纠错免费软件-文字校对软件免费下载
  • 【Redis】Redis缓存雪崩、缓存穿透、缓存击穿(热key问题)
  • 为什么很多程序员喜欢linux系统?
  • Bean 作用域和生命周期
  • PMP考试常见13个固定套路
  • Leecode101 ——对称二叉树
  • JVM学习随笔03——Java堆中new一个对象的步骤