前端性能优化之首屏加载【懒加载,监听元素视口可见,骨架屏优化白屏时长,长列表虚拟滚动,压缩图片,Tree shaking,base64】
目录路由懒加载SPA 一个路由对应一个页面把所有页面打包成一个文件懒加载前提ES6动态地加载模块——import()webpackChunkName分离到单独的 chunk组件懒加载webpackChunkName: dialogInfo适用场景体积大非首屏复用性高Tree shaking消除无用的 JS 代码减少代码体积原理ES6模块静态分析只适用于函数式编程骨架屏优化白屏时长虚拟列表大量数据长列表虚拟滚动只渲染可视区非可见区域的不渲染虚拟滚动插件Web Worker 优化长任务适用当任务的运算时长 - 通信时长 50msrequestAnimationFrame 制作动画刷新频率与显示器的频率保持一致优先级setTimeout/setInterval 属于 JS引擎requestAnimationFrame 属于 GUI引擎JS引擎与GUI引擎是互斥的 GUI 引擎在渲染时会阻塞 JS 引擎的计算时间requestAnimationFrame 刷新频率是固定且准确的setTimeout/setInterval 是宏任务性能setTimeout/setInterval 定时器仍会在后台执行动画任务requestAnimationFrame 当页面处于未激活的状态下屏幕刷新任务会被系统暂停列表以图片为例src属性src 自动发送请求、下载data-src 暂存 src 的值动态裁剪在图片url地址上动态添加参数懒加载/视口可见元素A.浏览器原生监听器a.scroll 视口顶部距离b.IntersectionObserver交叉观察器目标元素与父/视口产生交叉区常用函数使用this.$nextTick((){DOM更新后观察})参数B.框架插件a.vue-lazyload 插件小图片转 base64 编码无需请求原理图片的 二进制数据 的 字符串 表示形式图片大小-原文件的 4/3类似html中嵌入的文字因此无需单独文件无法缓存从而无需请求举例小图片小于 100KB如小图标、图像按钮、装饰性背景图经常用到如头像Data URL格式HTMLCSS方式a.FileReader 的 readAsDataURL()b.canvas.toDataURLc.url-loader 将图片转 base64懒/动态加载按需/运动加载路由懒加载SPA 一个路由对应一个页面把所有页面打包成一个文件如果不做处理项目打包后会把所有页面打包成一个文件当用户打开首页时会一次性加载所有的资源造成首页加载很慢降低用户体验懒加载前提ES6动态地加载模块——import()调用 import() 之处被作为分离的模块起点意思是被请求的模块和它引用的所有子模块会分离到一个单独的 chunk 中——摘自《webpack——模块方法》的import()小节webpackChunkName分离到单独的 chunk要实现懒加载就得先将进行懒加载的子模块分离出来打包成一个单独的文件webpackChunkName 作用是 webpack 在打包的时候对异步引入的库代码lodash进行代码分割时设置代码块的名字。webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中// 通过webpackChunkName设置分割后代码块的名字 const Home () import(/* webpackChunkName: home */ /views/home/index.vue); const MetricGroup () import(/* webpackChunkName: metricGroup */ /views/metricGroup/index.vue); ………… const routes [ { path: /, name: home, component: Home }, { path: /metricGroup, name: metricGroup, component: MetricGroup }, ………… ]组件懒加载webpackChunkName: dialogInfohome 页面 和 about 页面都引入了 dialogInfo 弹框组件该弹框不是一进入页面就加载而是需要用户手动触发后才展示出来script const dialogInfo () import(/* webpackChunkName: dialogInfo */ /components/dialogInfo); export default { name: homeView, components: { dialogInfo } } /script适用场景体积大该页面的 JS 文件体积大导致页面打开慢可以通过组件懒加载进行资源拆分利用浏览器并行下载资源提升下载速度比如首页非首屏该组件不是一进入页面就展示需要一定条件下才触发比如弹框组件复用性高该组件复用性高很多页面都有引入利用组件懒加载抽离出该组件一方面可以很好利用缓存同时也可以减少页面的 JS 文件大小比如表格组件、图形组件等Tree shaking消除无用的 JS 代码减少代码体积项目中只使用了 targetType 方法但未使用 deepClone 方法项目打包后deepClone 方法不会被打包到项目里// 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)); }原理ES6模块静态分析静态分析就是不需要执行代码就可以从字面量上对代码进行分析。ES6之前的模块化比如 CommonJS 是动态加载只有执行后才知道引用的什么模块就不能通过静态分析去做优化只适用于函数式编程无法通过静态分析判断出一个对象的哪些变量未被使用所以 tree-shaking 只对使用 export 导出的变量生效// 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)骨架屏优化白屏时长虚拟列表大量数据长列表虚拟滚动只渲染可视区非可见区域的不渲染计算出 totalHeight 列表总高度并在触发时滚动事件时根据 scrollTop 值不断更新 startIndex 以及 endIndex 以此从列表数据 listData 中截取对应元素虚拟滚动插件虚拟滚动的插件有很多比如 vue-virtual-scroller、vue-virtual-scroll-list、react-tiny-virtual-list、react-virtualizedWeb Worker 优化长任务由于浏览器 GUI 渲染线程与 JS 引擎线程是互斥的关系当页面中有很多长任务时会造成页面 UI 阻塞出现界面卡顿、掉帧等情况查看页面的长任务打开控制台选择 Performance 工具点击 Start 按钮展开 Main 选项会发现有很多红色的三角这些就属于长任务长任务执行时间超过50ms的任务适用当任务的运算时长 - 通信时长 50msTime 是这个资源的通信时长也叫加载时长requestAnimationFrame 制作动画刷新频率与显示器的频率保持一致可以解决用 setTimeout/setInterval 制作动画卡顿的情况优先级setTimeout/setInterval 属于JS引擎requestAnimationFrame 属于GUI引擎JS引擎与GUI引擎是互斥的 GUI 引擎在渲染时会阻塞 JS 引擎的计算时间requestAnimationFrame 刷新频率是固定且准确的setTimeout/setInterval 是宏任务根据事件轮询机制其他任务会阻塞或延迟js任务的执行会出现定时器不准的情况性能当页面被隐藏或最小化时setTimeout/setInterval 定时器仍会在后台执行动画任务requestAnimationFrame 当页面处于未激活的状态下屏幕刷新任务会被系统暂停列表以图片为例src属性src 自动发送请求、下载data-src 暂存 src 的值HTML5自定义属性data-xxx主要用于在 DOM 元素中存储额外的信息而不会自动请求资源在图片出现在屏幕可视区域的时候再将>img src alt>动态裁剪在图片url地址上动态添加参数比如阿里云或七牛云都提供了图片的动态裁剪功懒加载/视口可见元素(Load On Demand)延迟加载、按需加载可视化区域之外的图片不会进行加载在滚动屏幕时才加载。这样使得网页的加载速度更快减少了服务器的负载。懒加载适用于图片较多页面列表较长(长列表)的场景中。A.浏览器原生监听器节流和防抖能减少执行次数但不能消除scroll频繁触发的本质IntersectionObserver在浏览器的层面处理可见性检测能够批量处理多个观察者的状态变化减少计算和触发的频率IntersectionObserver2016 年( Chrome 51 和 Firefox 55因此scroll更兼容a.scroll 视口顶部距离使用场景检测滚动位置存储初始边界值滚动会更改相应距离位置scroll回调放在requestAnimationFrame中以在浏览器下次重绘前执行!DOCTYPE html html langen head meta charsetUTF-8 meta http-equivX-UA-Compatible contentIEedge meta nameviewport contentwidthdevice-width, initial-scale1.0 titleDocument/title style .scrollBox { width: 100%; height: 300px; background-color: #ccc; overflow-y: auto; } .target { width: 60px; height: 60px; background-color: red; } /style /head body h1孙悟空/h1 h1孙悟空/h1 div classscrollBox h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 div classtarget/div /div h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 h1孙悟空/h1 script const scrollBoxDom document.querySelector(.scrollBox); const targetDom document.querySelector(.target); let lastKnownScrollPosition 0; let ticking false; // 计算边界值 const boundaryValue targetDom.getBoundingClientRect().top - scrollBoxDom.getBoundingClientRect().top - scrollBoxDom.offsetHeight; function handleScroll(scrollPos) { if (scrollPos boundaryValue) { console.log(在可视区域); scrollBoxDom.style.backgroundColor pink; } else { console.log(不在可视区域); scrollBoxDom.style.backgroundColor #ccc; } } // 防抖函数 function debounce(func, wait) { let timeout; return function (...args) { const context this; clearTimeout(timeout); timeout setTimeout(() func.apply(context, args), wait); }; } // 创建防抖后的处理函数 const debouncedScroll debounce(function () { if (!ticking) { window.requestAnimationFrame(function () { handleScroll(lastKnownScrollPosition); ticking false; }); ticking true; } }, 100); // 100ms 的防抖时间 scrollBoxDom.addEventListener(scroll, function () { lastKnownScrollPosition scrollBoxDom.scrollTop; debouncedScroll(); }); /script /body /html图片的 src 属性设为默认图片图片的真实路径则设置在data-src属性中绑定 window 的scroll事件对其进行事件监听。//节流 window.addEventListener(scroll, throttle(lazyload, 200))在scroll事件的回调中判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内将图片的 src 属性设置为data-src的值html langen head meta charsetUTF-8 titleLazyload/title style .image-item { display: block; margin-bottom: 50px; height: 200px;//一定记得设置图片高度 } /style /head body img src./img/default.png>b.IntersectionObserver交叉观察器目标元素与父/视口产生交叉区使用场景懒加载图片、实现无限滚动、检测元素可见性等常用函数//创建观察器new IntersectionObserver(callback, options) var io new IntersectionObserver(callback, option) // 绑定观察元素 observer.observe(dom) io.observe(document.getElementById(example)) // 停止观察 io.unobserve(element) // 关闭观察器 io.disconnect()使用this.$nextTick((){DOM更新后观察})//列表发生变化时调用handleObserver() handleObserver(){ if (!this.observer) { this.observer new IntersectionObserver((entries, self) { entries.forEach((entry) { if (entry.isIntersecting) { let img entry.target let src img.dataset.src if (src) { img.src src img.removeAttribute(data-src) } // 解除观察 self.unobserve(entry.target) } }) }) } // DOM 更新后执行 this.$nextTick(() { imgs.forEach((image) { let dom document.getElementById(image.id); if (dom) { observer.observe(dom); } }) }); }参数callback 是可见性变化时的回调函数option 是配置对象可选callback触发时机刚进入视口开始可见完全离开视口开始不可见var observer new IntersectionObserver(function(entriesobserver/self){ //回调函数参数entries 被观察IntersectionObserverEntry对象数组观察器 }, options)IntersectionObserverEntry 对象的属性常用isIntersecting: 目标是否可见target被观察的目标元素是一个 DOM 节点对象其他time可见性发生变化的时间是一个高精度时间戳单位为毫秒rootBounds根元素的矩形区域的信息getBoundingClientRect()方法的返回值如果没有根元素即直接相对于视口滚动则返回 nullboundingClientRect目标元素的矩形区域的信息intersectionRect目标元素与视口或根元素的交叉区域的信息intersectionRatio目标元素的可见比例即intersectionRect占boundingClientRect的比例完全可见时为 1完全不可见时小于等于 0options配置对象//默认值 const options { root: null, // 默认为整个文档视口;若设置祖先级对象主要的是针对局部的滚动效果 rootMargin: 0px,//视口外延像素 threshold: 0 // 目标元素可见度的阈值范围0刚进入到 1完全可见 }; const observer new IntersectionObserver(callback, options);B.框架插件a.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-forimg in list img v-lazyimg.src :keyimg.src /li /ul前端性能优化之图片懒加载 - 掘金预加载某图片加载时机方法加载时机推荐度CSS 隐藏但渲染页面加载时★★★☆☆link relpreload文档解析早期★★★★★JSnew Image()JS执行时加载好再显示★★★★☆link relpreload!-- 在HTML head中 -- link relpreload hrefimage.jpg asimageJSnew Image()加载完再显示div v-showimageLoaded classglobal-modal :classmodalClass :stylemodalStyle data() { return { imageLoaded: false } } mounted() { if (this.theme img) { const img new Image(); img.onload () { this.imageLoaded true; }; img.src require(/assets/images/v3/certificate_bg.png); } else { this.imageLoaded true; } }CSS 隐藏但渲染/* 创建一个渲染但不可见的元素 */ .preload-images { position: absolute; width: 0; height: 0; overflow: hidden; z-index: -1; opacity: 0.001; /* 几乎透明但确保渲染 */ /* 关键不要用 display: none */ background: url(/assets/images/bg1.jpg), url(/assets/images/bg2.jpg), url(/assets/images/bg3.jpg); }小图片转 base64 编码无需请求原理图片的 二进制数据 的 字符串 表示形式图片大小-原文件的 4/3类似html中嵌入的文字因此无需单独文件无法缓存从而无需请求举例小图片小于 100KB如小图标、图像按钮、装饰性背景图经常用到如头像Data URL格式HTMLimg srcdata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA... altEmbedded ImageCSSbackground-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA...);方式a.FileReader的readAsDataURL()getBase64(file: any) { //转化base64 let _ this; return new Promise((resolve, reject) { let reader: any new FileReader(); let base64 ; reader.readAsDataURL(file); //开始转 reader.onload function() { base64 reader.result; }; //转 失败 reader.onerror function(error: any) { reject(error); }; //转 结束 resolve 出去 reader.onloadend function() { resolve(base64); }; }); },b.canvas.toDataURLc.url-loader将图片转 base64参考链接前端性能优化——首页资源压缩63%、白屏时间缩短86% - 掘金

相关新闻

为什么选择DTS-SHOP?5大优势让你的微信小程序商城脱颖而出

为什么选择DTS-SHOP?5大优势让你的微信小程序商城脱颖而出

为什么选择DTS-SHOP?5大优势让你的微信小程序商城脱颖而出 【免费下载链接】dts-shop 微信小程序,小程序商城,商城,springboot框架,vue管理系统,java后台 项目地址: https://gitcode.com/gh_mirrors/dt/d…

2026/7/21 20:13:59 阅读更多 →
Ruby分布式计算解决方案:Spark与Ruby集成完全教程

Ruby分布式计算解决方案:Spark与Ruby集成完全教程

Ruby分布式计算解决方案:Spark与Ruby集成完全教程 【免费下载链接】data-science-with-ruby Practical Data Science with Ruby based tools. 项目地址: https://gitcode.com/gh_mirrors/da/data-science-with-ruby 想要在大数据时代使用Ruby进行分布式计算吗…

2026/7/21 20:13:59 阅读更多 →
Jupynium.nvim 常见问题解答:解决安装、配置与使用中的难题

Jupynium.nvim 常见问题解答:解决安装、配置与使用中的难题

Jupynium.nvim 常见问题解答:解决安装、配置与使用中的难题 【免费下载链接】jupynium.nvim Selenium-automated Jupyter Notebook that is synchronised with Neovim in real-time. 项目地址: https://gitcode.com/gh_mirrors/ju/jupynium.nvim Jupynium.nv…

2026/7/21 20:13:59 阅读更多 →

最新新闻

树结构算法:核心价值与高频解题模板

树结构算法:核心价值与高频解题模板

1. 树结构刷题的核心价值在算法面试和编程竞赛中,树结构题目出现的频率仅次于数组和字符串。我完整刷完LeetCode树类题库后,发现这类题目具有独特的训练价值:它们能同时考察递归思维、边界条件处理能力,以及对空间/时间复杂度的精…

2026/7/21 23:27:03 阅读更多 →
DCS World模拟飞行MFCD外设自制指南:树莓派与ESP32方案详解

DCS World模拟飞行MFCD外设自制指南:树莓派与ESP32方案详解

这次我们来看一个硬核的飞行模拟外设自制项目:如何为《数字战斗模拟世界》(DCS World)打造专属的MFCD(多功能控制显示器)外设。对于DCS玩家来说,座舱内那些密密麻麻的MFCD屏幕是获取飞行信息、操作武器系统…

2026/7/21 23:27:03 阅读更多 →
车载无线通信模块兼容性设计与优化实践

车载无线通信模块兼容性设计与优化实践

1. 车载移动终端无线通信模块的行业痛点在车载电子设备领域,移动终端需要适配多种无线通信模块(如3G/4G模块)早已成为行业常态。我参与过多个车载项目开发,最头疼的就是不同运营商、不同制式的模块兼容问题。常见的情况是&#xf…

2026/7/21 23:27:03 阅读更多 →
AI原生组织:人机协作的新形态

AI原生组织:人机协作的新形态

很多企业在推进AI落地的过程中,常会遇到一个共性问题:零散的AI工具很难真正融入团队的日常协作流程,反而容易变成员工额外的操作负担。向量空间JBoltAI在长期的实践观察中发现,AI落地的核心从来不是单一工具的堆叠,而是…

2026/7/21 23:27:03 阅读更多 →
企业大脑:企业的认知基础设施

企业大脑:企业的认知基础设施

很多企业在数字化建设过程中,已经搭建起了成熟的ERP等各类运营系统,这些系统负责记录流程、执行操作,支撑着日常业务的有序运转。但不少团队会慢慢发现,这些系统更偏向"执行层"的运营支撑,很难自主完成对全局…

2026/7/21 23:27:03 阅读更多 →
北京标书撰写服务对比:专业团队如何助你高效中标

北京标书撰写服务对比:专业团队如何助你高效中标

在当今竞争激烈的商业环境中,招投标已成为企业获取项目的重要途径。一份高质量的标书,往往是决定投标成败的关键因素。随着市场需求增长,专业标书撰写服务应运而生,为企业提供从方案策划到文件编制的全方位支持。本文将客观分析当…

2026/7/21 23:26:03 阅读更多 →

日新闻

Octane Render与C4D汉化版安装与优化指南

Octane Render与C4D汉化版安装与优化指南

1. Octane Render与C4D的黄金组合:为什么选择这个方案?在三维创作领域,渲染器的选择往往决定了作品的最终呈现质量和工作效率。作为Cinema 4D(C4D)用户,Octane Render的GPU加速特性与实时预览功能&#xff…

2026/7/21 0:00:19 阅读更多 →
GPMC接口设计:异步/同步模式与多路复用配置实战

GPMC接口设计:异步/同步模式与多路复用配置实战

1. GPMC接口设计:从硬件连接到软件配置的全局视角在嵌入式系统开发中,尤其是基于TI Sitara系列如AM263x这类高性能微控制器的项目里,外部存储器的扩展几乎是绕不开的一环。无论是存放大量非易失性代码的NOR Flash,还是作为高速数据…

2026/7/21 0:00:19 阅读更多 →
UE5 GAS框架下RPG被动技能系统:从核心原理到实战实现

UE5 GAS框架下RPG被动技能系统:从核心原理到实战实现

1. 项目概述:UE5 GAS RPG被动技能的核心价值在UE5里用GAS(Gameplay Ability System)做RPG游戏,主动技能像是你手里的武器,按一下打一下,逻辑直接,反馈也快。但被动技能,它更像是你身…

2026/7/21 0:00:19 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/21 8:48:31 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/21 5:34:47 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/21 8:25:39 阅读更多 →

月新闻