导图社区 C.性能优化
前端面试:性能优化 场景题,总结了前端面试中性能优化场景题的各个方面,从基础原理到具体优化技术和实际场景应用,有助于面试者系统地准备和应对相关问题。
编辑于2025-07-02 21:59:38这是一个关于D.Vuereact的思维导图,细致罗列了相关的技术要点与面试常见问题,结构清晰、内容全面,宛如一把开启前端面试成功之门的钥匙,为前端求职者提供了系统且高效的知识复习体系。对于即将踏入前端面试战场的学生和求职者来说,这是绝佳的备考神器。在前端技术日新月异的当下,面试不仅考察基础知识的掌握,更注重对流行框架和技术的理解与应用。这张思维导图紧扣前端面试热点,涵盖了主流前端框架Vue3、React、angular的核心概念、生命周期、组件通信等关键知识,以及uni-app跨平台开发、微信小程序开发的要点内容。求职者可以依据此图进行针对性复习,快速梳理知识脉络,查漏补缺,将各个知识点融会贯通,在面试中更加游刃有余地回答技术问题,展示自己的专业能力。在日常学习场景中,前端初学者也能借助此图明确学习重点,了解前端技术体系的全貌。图中丰富的知识点以简洁明了的文字呈现,便于理解和记忆。使用EdrawMind可轻松绘制此类面试知识导图,让复杂知识一目了然,助力用户高效备考前端面试,斩获心仪的offer。
这是一个关于B.工程化Webpackvite的思维导图,将前端工程化中Webpack+Vite、浏览器原理、前端架构设计、微前端等核心板块的知识要点进行了系统整合与细致梳理,结构清晰,层次分明,宛如一位无声的学习导师,为前端学习者指明知识探索的方向。对于即将参加前端面试的求职者而言,这是不可多得的备考利器。在竞争激烈的前端招聘市场中,对前端工程化知识的深入理解与熟练掌握是脱颖而出的关键。这张思维导图涵盖了前端工程化的多个重要方面,从Webpack和Vite的打包原理、常见配置,到浏览器渲染机制、安全原理;从前端架构设计的定义、实现方式,到微前端的概念、应用场景等,一应俱全。求职者可以依据此图进行全面复习,查漏补缺,将碎片化的知识串联起来,形成完整的知识体系,从而在面试中更加从容自信地回答相关问题。在日常学习场景中,前端初学者也能借助此图快速把握前端工程化的重点内容,明确学习路径。图中丰富的知识点以简洁明了的文字呈现,便于理解和记忆。使用EdrawMind可高效绘制此类知识梳理导图,让复杂知识一目了然,助力用户轻松攻克前端工程化难关。
这是一个关于A.htmljstses的思维导图,将HTML+CSS、JavaScript、jQuery等Web前端核心知识进行了系统梳理,结构清晰明了,宛如一幅知识地图,为Web前端学习者勾勒出了一条清晰的学习路径。对于Web前端领域的学生和初学者而言,这是开启学习之旅的绝佳指南。在当今互联网高速发展的时代,Web前端开发作为构建精美网页和交互式应用的关键技术,备受关注。然而,前端知识体系庞大且复杂,初学者往往不知从何入手。这张思维导图恰好解决了这一难题,它从基础的HTML+CSS开始,逐步延伸到JavaScript的语法、函数、对象等核心内容,再到jQuery的选择器、事件、动画等实用技巧,涵盖了Web前端开发的各个方面。在学习场景中,学生可以依据此图制定合理的学习计划,按照知识点的层级关系循序渐进地学习。每个知识点都以简洁的文字标注在节点上,方便学生快速理解和记忆。同时,对于准备面试的求职者来说,这也是一份高效的复习资料,能够帮助他们系统地回顾和巩固所学知识。使用EdrawMind可轻松绘制此类知识体系导图,让复杂知识一目了然,助力用户高效学习Web前端技术。
社区模板帮助中心,点此进入>>
这是一个关于D.Vuereact的思维导图,细致罗列了相关的技术要点与面试常见问题,结构清晰、内容全面,宛如一把开启前端面试成功之门的钥匙,为前端求职者提供了系统且高效的知识复习体系。对于即将踏入前端面试战场的学生和求职者来说,这是绝佳的备考神器。在前端技术日新月异的当下,面试不仅考察基础知识的掌握,更注重对流行框架和技术的理解与应用。这张思维导图紧扣前端面试热点,涵盖了主流前端框架Vue3、React、angular的核心概念、生命周期、组件通信等关键知识,以及uni-app跨平台开发、微信小程序开发的要点内容。求职者可以依据此图进行针对性复习,快速梳理知识脉络,查漏补缺,将各个知识点融会贯通,在面试中更加游刃有余地回答技术问题,展示自己的专业能力。在日常学习场景中,前端初学者也能借助此图明确学习重点,了解前端技术体系的全貌。图中丰富的知识点以简洁明了的文字呈现,便于理解和记忆。使用EdrawMind可轻松绘制此类面试知识导图,让复杂知识一目了然,助力用户高效备考前端面试,斩获心仪的offer。
这是一个关于B.工程化Webpackvite的思维导图,将前端工程化中Webpack+Vite、浏览器原理、前端架构设计、微前端等核心板块的知识要点进行了系统整合与细致梳理,结构清晰,层次分明,宛如一位无声的学习导师,为前端学习者指明知识探索的方向。对于即将参加前端面试的求职者而言,这是不可多得的备考利器。在竞争激烈的前端招聘市场中,对前端工程化知识的深入理解与熟练掌握是脱颖而出的关键。这张思维导图涵盖了前端工程化的多个重要方面,从Webpack和Vite的打包原理、常见配置,到浏览器渲染机制、安全原理;从前端架构设计的定义、实现方式,到微前端的概念、应用场景等,一应俱全。求职者可以依据此图进行全面复习,查漏补缺,将碎片化的知识串联起来,形成完整的知识体系,从而在面试中更加从容自信地回答相关问题。在日常学习场景中,前端初学者也能借助此图快速把握前端工程化的重点内容,明确学习路径。图中丰富的知识点以简洁明了的文字呈现,便于理解和记忆。使用EdrawMind可高效绘制此类知识梳理导图,让复杂知识一目了然,助力用户轻松攻克前端工程化难关。
这是一个关于A.htmljstses的思维导图,将HTML+CSS、JavaScript、jQuery等Web前端核心知识进行了系统梳理,结构清晰明了,宛如一幅知识地图,为Web前端学习者勾勒出了一条清晰的学习路径。对于Web前端领域的学生和初学者而言,这是开启学习之旅的绝佳指南。在当今互联网高速发展的时代,Web前端开发作为构建精美网页和交互式应用的关键技术,备受关注。然而,前端知识体系庞大且复杂,初学者往往不知从何入手。这张思维导图恰好解决了这一难题,它从基础的HTML+CSS开始,逐步延伸到JavaScript的语法、函数、对象等核心内容,再到jQuery的选择器、事件、动画等实用技巧,涵盖了Web前端开发的各个方面。在学习场景中,学生可以依据此图制定合理的学习计划,按照知识点的层级关系循序渐进地学习。每个知识点都以简洁的文字标注在节点上,方便学生快速理解和记忆。同时,对于准备面试的求职者来说,这也是一份高效的复习资料,能够帮助他们系统地回顾和巩固所学知识。使用EdrawMind可轻松绘制此类知识体系导图,让复杂知识一目了然,助力用户高效学习Web前端技术。
性能优化+场景
性能优化
九、服务器优化
1.静态资源使用 CDN
用户与服务器的物理距离对响应时间也有影响。把内容部署在多个地理位置分散的服务器上能让用户更快地载入页面, CDN就是为了解决这一问题,在多个位置部署服务器,让用户离服务器更近,从而缩短请求时间。
2.添加Expires或者Cache-Control响应头
使用cach-control或expires这类强缓存时,缓存不过期的情况下,不向服务器发送请求。强缓存过期时,会使用last-modified或etag这类协商缓存,向服务器发送请求,如果资源没有变化,则服务器返回304响应,浏览器继续从本地缓存加载资源;如果资源更新了,则服务器将更新后的资源发送到浏览器,并返回200响应。
3.对组件使用Gzip压缩
4.配置ETag
Entity tags(ETags)(实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制(“实体”就是所说的“内 容”,包括图片、脚本、样式表等)。增加ETag为实体的验证提供了一个比使用“last-modified date(上次编辑时间)”更加灵活的机制。Etag是一个识别内容版本号的唯一字符串。唯一的格式限制就是它必须包含在双引号内。原始服务器通过含有 ETag文件头的响应指定页面内容的ETag。
5.提供来自相同协议的文件
避免网站使用HTTPS同时使用HTTP来提供相同源地址的文件。
6.开启http2(多路复用,并行加载)
HTTP2带来了非常大的加载优化,所以在做优化上首先就想到了用HTTP2代替HTTP1。
7.服务端渲染
服务端返回 HTML 文件,客户端只需解析 HTML。首屏渲染快,SEO 好。
缺点:配置麻烦,增加了服务器的计算压力。
8.分域存放资源
由于浏览器同一域名并行下载数有限,利用多域名主机存放静态资源,增加并行下载数,缩短资源加载时间。
9.减少页面重定向
1.第一次访问时的优化(把第一次的加载速度变快)
1.代码压缩和合并
压缩JavaScript、CSS文件,减少文件大小和HTTP请求数量
1.首屏优化速度、白屏时间
最大效果就是要减少首屏资源体积
- 打包工具的压缩 - 异步加载(体积大但是又不是马上要用的) - 更新为提及更小的新版本,能不用第三方库的就不用,自己编写,比如时间格式化的,编写代码尽量减少体积 - 去除大的base64体积:打包后,小图片会转成base64,但是一些配置如果配错的话,大图片也会转成的
收效不大或者特殊情况的优化操作
首屏数据尽量并行,如果可行小数据接口合并; 页面包含大量dom可以分批滚动渲染; 骨架屏,Loading:先让屏幕不白,减少用户焦虑
页码渲染优化
优化 html 代码
js 外连接放在底部; css 外连接放在顶部; 减少DOM数量
优化js/css代码
使用 webworker; 场任务分片执行; 减少重拍、重绘降低 css选择器复杂性
优化动画效果
资源加载优化
减少资源大小
代码压缩; Gzip 图片压缩 代码拆分
减少 Http 请求次数
http强缓存; serviceWorker; 本地存储; 合并请求(雪碧图等)
提升 Http 请求响应速度
CDN
Http 弱缓存
DNS Prefetch
Http2
优化资源加载时机
按需加载;懒加载;预加载
优化资源、内容加载方式
客户端内H5页面可以考虑离线宝等方式
内容直出
UI 框架按需加载
2.图片优化
使用合适的图片格式(如WebP),对图片进行压缩,在不影响视觉效果的前提下减小图片大小。
3.懒加载
对于图片、视频等资源,采用懒加载技术,只有当元素进入视口时才加载资源。
4.服务端渲染(SSR)或预渲染
SSR可以在服务器端生成HTML内容直接发送给客户端,预渲染则是预先生成静态HTML文件,这两种方式都可以加快首次加载速度。
2.第n次访问时的优化(把已经访问过的资源缓存);
一般情况下,访问过的页面/资源,想要在后面访问时加快访问速度,可以想到的方式是利用缓存或本地存储;
前端本身我们可以通过不同的业务逻辑利用localStorage或sessionStorage 就可以了
如何涉及到服务端,我们也可以采用http的缓存,一般有两种方式,一个是强缓存、另一个是协商缓存,强缓存的优先级高于协商缓存,我们可以通过相关key去设置缓存时间(那么多属性不一定记得住,但一定要知道有这个东西)
除了本地存储和http缓存,也可以尝试采用indexDB去做前端的数据存储
除了indexBD,Service workers也可以作为缓存方案
3.让用户感觉很快,很流畅(通过交互手段优化体验)
让用户感觉很快,顾名思义,就是并没有实际上的提升速度,而是优化了用户体验,可以采用骨架屏、懒加载、合理loading,防抖、节流
什么情况下造成操作卡顿和渲染慢?
一次性操作大量dom,比如长列表渲染,异步渲染
进行复杂度很高的运算(比如循环)
vue和react项目中,不必要的渲染太多
- v-show:频繁切换的;v-if :一次性的 - 循环和动态切换内容加好key值 - keep-alive 缓存,要慎用 - 区分请求粒度,减少请求范围,也能减少更新(没必要更新的接口就不要更新了,比如删除后,只更新列表,搜索分类的就没必要了)
css加载会造成阻塞吗?
结论
css加载不会阻塞DOM树的解析; css加载会阻塞DOM树的渲染; css加载会阻塞后面js语句的执行。
为了避免让用户看到长时间的白屏时间,我们应该尽可能的提高css加载速度
1.使用CDN(因为CDN会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间) 2.对css进行压缩(可以用很多打包工具,比如webpack,gulp等,也可以通过开启gzip压缩) 3.合理的使用缓存(设置cache-control,expires,以及E-tag都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号) 4.减少http请求数,将多个css文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存)
原理解析
浏览器渲染的流程如下: HTML解析文件,生成DOM Tree,解析CSS文件生成CSSOM Tree 将Dom Tree和CSSOM Tree结合,生成Render Tree(渲染树) 根据Render Tree渲染绘制,将像素渲染到屏幕上。
从流程我们可以看出来: DOM解析和CSS解析是两个并行的进程,所以这也解释了为什么CSS加载不会阻塞DOM的解析。 然而,由于Render Tree是依赖于DOM Tree和CSSOM Tree的,所以他必须等待到CSSOM Tree构建完成,也就是CSS资源加载完成(或者CSS资源加载失败)后,才能开始渲染。因此,CSS加载是会阻塞Dom的渲染的。 由于js可能会操作之前的Dom节点和css样式,因此浏览器会维持html中css和js的顺序。因此,样式表会在后面的js执行前先加载执行完毕。所以css会阻塞后面js的执行。
首屏加载速度慢怎么解决?
一、什么是首屏加载
指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容 首屏加载可以说是用户体验中最重要的环节
二、加载慢的原因
1.网络延时问题
cdn,用户节点就近
preload 预加载
prereder 预渲染
2. 资源太大
a.包分chunk
b.懒加载
c.公共资源 vender
d.缓存(不变动的使用强缓存;变动的使用协商缓存; 离线环境下使用策略缓存,service-worker)
e.服务端渲染(DOM树在服务端生成,然后返回给前端。)
f. 局部SSR,(广告页/营销活动页等)
3.资源是否重复发送请求去加载了
4.加载脚本的时候,渲染内容堵塞了
三、解决方案
减小入口文件积
常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,使得入口文件变小,加载速度大大增加; 在vue-router配置路由的时候,采用动态加载路由的形式: routes:[ path: 'Blogs', name: 'ShowBlogs', component: () => import('./components/ShowBlogs.vue') ] 以函数的形式加载路由,这样就可以把各自的路由文件分别打包,只有在解析给定的路由时,才会加载路由组件
静态资源本地缓存
采用HTTP缓存
采用Service Worker离线缓存
前端合理利用localStorage
UI框架按需加载
图片资源的压缩
图片资源虽然不在编码过程中,但它却是对页面性能影响最大的因素 对于所有的图片资源,我们可以进行适当的压缩 对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。
组件重复打包
假设A.js文件是一个常用的库,现在有多个路由使用了A.js文件,这就造成了重复下载 解决方案:在webpack的config文件中,修改CommonsChunkPlugin的配置 minChunks: 3 表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件
开启GZip压缩
使用SSR,也就是服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器
指标
First Contentful Paint (FCP) - 首次内容绘制时间
衡量从开始加载页面到页面上的第一个内容元素(如文本、图像、SVG 等)绘制到屏幕上的时间。这是用户感知到的第一个信号,表明页面开始加载内容。
Largest Contentful Paint (LCP) - 最大内容绘制时间:
衡量页面上最大的内容元素(通常是一个大的图片或视频背景)从开始加载到渲染完成的时间。LCP 是一个关键的用户体验指标,因为它反映了页面主要内容的加载速度。
First Meaningful Paint (FMP) - 首次有意义绘制时间
这一指标虽然不是官方标准的一部分,但它是评估页面何时变得有用的一个度量。它衡量的是页面首次呈现有意义的内容给用户的时间,即页面的主要内容已加载完毕并且视觉上稳定的时间。
Time to Interactive (TTI) - 交互就绪时间
衡量页面从开始加载到完全可用、响应用户输入所需的时间。在这段时间之后,页面应该可以快速响应用户的点击、触摸等交互。
Total Blocking Time (TBT) - 总阻塞时间
衡量从 FCP 到 TTI 之间,页面被认为是不可响应的时间总和。这个指标帮助识别那些使得页面无法立即响应用户输入的长时间任务。
Speed Index (SI) - 速度指数
速度指数是一种量化指标,它衡量页面内容在多快的时间内出现在可视区域。它记录了页面在一定时间内渲染了多少像素。
Cumulative Layout Shift (CLS) - 累积布局偏移
这是一个用户体验指标,用于测量页面在加载过程中发生的意外布局变化的程度。良好的 CLS 分数表示页面在加载期间保持了视觉稳定性。
First Byte Time (TTFB) - 第一个字节时间
衡量从浏览器发送请求到服务器返回第一个字节数据的时间。TTFB 反映了服务器端处理请求的速度以及网络延迟。
一、感知性能优化
1.loading
2.骨架屏
二、HTML优化
1.压缩 HTML
HTML代码压缩,将注释、空格和新行从生产文件中删除。删除所有不必要的空格、注释和中断行将减少HTML的大小,加快网站的页面加载时间,并显著减少用户的下载时间。
2.删除不必要的注释
注释对用户来说是没有用的,应该从生产环境文件中删除。可能需要保留注释的一种情况是:保留远端代码库(keep the origin for a library)。
我们可以使用HTML minify插件删除注释。(使用 remove-html-comments - npm)
3.删除不必要的属性
<!-- Before HTML5 --> <script type="text/javascript"></script> <!-- Today --> <script></script>
4.使用语义化标签
使用语义化标签可以提高代码的可读性和可维护性,并有助于搜索引擎优化。例如,使用 标签来定义页面头部,使用 标签来定义导航等。
5.减少iframe数量
尽量少用iframe标签,爬虫是不会读取iframe的内容的。
6..削减DOM数量和层级数量
HTML 中标签元素越多,标签的层级越深,浏览器解析 DOM 并制作到浏览器中所花的时间就越长,所以应尽或许坚持 DOM 元素简洁和扁平化的层级。
7.减少 HTTP 请求次数
将多个 CSS 和 JavaScript 文件合并为一个文件,可以减少 HTTP 请求次数,从而提高页面加载速度。同时,使用浏览器缓存可以避免每次请求相同的文件。
8.减少重排重绘
三、JavaScript优化
1.js脚本放到页面底部
将<script>标签尽量尽可能放到<body>标签的底部。
2.将js和css从外部引入
3.删除重复的脚本
4.减少DOM访问
6.合理的ajax恳求
7.长列表虚拟滚动优化
8 .代码结构的优化
1.设置Viewport:HTML的viewport可加快页面的渲染。 2.减少DOM结点:DOM结点太多会影响页面的渲染。 3.尽量使用css3动画:合理使用requestAnimationFrame动画代替setTimeout。 4.优化高频事件:scroll、touchmove等事件尽量使用函数防抖节流等进行限制。 5. 不滥用WEB字体:WEB字体需要下载、解析、重绘当前页面,尽量减少使用。 6. 文件命名规则须统一且要有意义,同类型文件归类到相同的文件夹中。 7. 删除无效注释。
四、CSS优化
1. 尽量少用@import
1.使用@import引入CSS会影响浏览器的并行下载。使用@import引用的CSS文件只有在引用它的那个css文件被下载、解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析、构建render tree等一系列操作。这就导致浏览器无法并行下载所需的样式文件。
2.多个@import会导致下载顺序紊乱。在IE中,@import会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件先于@import下载,并且打乱甚至破坏@import自身的并行下载。
2.避免!important,可以选择其他选择器
3.不要在ID选择器前面进行嵌套其它选择器
4.CSS文件压缩
5.CSS层级嵌套最好不要超过3层
6.删除无用的css
7.慎用*通配符
8.删除不必要的单位和零
9.异步加载非首屏css
10.将样式表放到页面顶部
五、图片优化
1.图片懒加载:loading="lazy"
2.检测是否到达视窗 需要:旧浏览器需要降级处理
3.滚动事件监听
4.使用库:lazyize/lazyload
常规
1.压缩图片
2.小图片引入雪碧图
4.img图片的alt属性要写
5.采用svg图片或者字体图标
6.Base64
六、webpack构建优化
指优化webpack的输出结果,让打包的最终结果在浏览器运行快速高效。
1. 线程加载器
多线程可以提高程序的效率
2. 缓存加载器
在我们的项目开发过程中,Webpack 需要多次构建项目。为了加快后续构建,我们可以使用缓存,与缓存相关的加载器是缓存加载器。
3.Hot update
当我们在项目中修改一个文件时,Webpack 默认会重新构建整个项目,但这并不是必须的。我们只需要重新编译这个文件,效率更高,这种策略称为Hot update。Webpack 内置了Hot update插件,我们只需要在配置中开启Hot update即可。
4.exclude & include
一些文件和文件夹永远不需要参与构建。所以我们可以在配置文件中指定这些文件,防止Webpack取回它们,从而提高编译效率。
1.exclude : 不需要编译的文件。
2.include : 需要编译的文件。
5.缩小 CSS 代码
压缩和去重 CSS 代码
6.缩小 JavaScript 代码
压缩和去重 JavaScript 代码。
7.tree-shaking
作用是把js文件中无用的模块或者代码删掉。而这通常需要借助一些工具。在webpack中tree-shaking就是在打包时移除掉javascript上下文中无用的代码,从而优化打包的结果。在webpack5中已经自带tree-shaking功能,在打包模式为production时,默认开启 tree-shaking功能。
8.source-map
当我们的代码出现bug时,source-map可以帮助我们快速定位到源代码的位置。但是这个文件很大。因此根据不同的环境来配置。
开发模式:生成更准确(但更大)
module.exports = { mode: 'development', devtool: 'eval-cheap-module-source-map' }
生产方式: 生成更小(但不那么准确)
module.exports = { mode: 'production', devtool: 'nosources-source-map' }
9.Bundle Analyzer
我们可以使用 webpack-bundle-analyzer 来查看打包后的 bundle 文件的体积,然后进行相应的体积优化。
10.模块懒加载
如果模块没有延迟加载,整个项目的代码会被打包成一个js文件,导致单个js文件体积非常大。那么当用户请求网页时,首屏的加载时间会更长。
使用模块来加载后,大js文件会被分割成多个小js文件,加载时网页按需加载,大大提高了首屏的加载速度。
11.压缩包
Gzip是一种常用的文件压缩算法,可以提高传输效率。但是,此功能需要后端配合。
12.base64
对于一些小图片,可以转成base64编码,这样可以减少用户的HTTP请求次数,提升用户体验
13.正确配置哈希
我们可以将哈希添加到捆绑文件中,这样可以更轻松地处理缓存。
output: { path: path.resolve(__dirname, '../dist'), filename: 'js/chunk-[contenthash].js', clean: true, },
七、资源加载优化
1.使用 Web Workers
Web Worker 是一个独立的线程(独立的执行环境),这就意味着它可以完全和 UI 线程(主线程)并行的执行 js 代码,从而不会阻塞 UI,它和主线程是通过 onmessage 和 postMessage 接口进行通信的。
Web Worker 使得网页中进行多线程编程成为可能。当主线程在处理界面事件时,worker 可以在后台运行,帮你处理大量的数据计算,当计算完成,将计算结果返回给主线程,由主线程更新 DOM 元素。
2.DNS预解析
浏览器对网站第一次的域名DNS解析查找流程依次为:
浏览器缓存 ->系统缓存 ->路由器缓存 ->ISP DNS缓存 ->递归搜索
DNS预解析的实现:
用meta信息来告知浏览器, 当前页面要做DNS预解析: <meta http-equiv="x-dns-prefetch-control" content="on" />
在页面header中使用link标签来强制对DNS预解析: <link rel="dns-prefetch" href="https://code-nav.top" />
dns-prefetch最大的缺点就是使用它太多。过多的预获取会导致过量的DNS解析,对网络是一种负担
3.预加载 preload
1.遇到link标签时,立刻下载并放到内存中,不执行js。
2.遇到script标签时,将预加载的js执行。
3.对跨域的文件进行preload时,必须加上 crossorigin 属性
<link rel="preload" crossorigin href="./zone.js" as="script">
基于标记语言的异步加载:
<link rel="preload" as="style" href="asyncstyle.css" onload="this.rel='stylesheet'">
如何对大型前端项目进行性能剖析(profiling)?
1.使用Chrome DevTools中的Performance面板。可以记录页面加载和交互过程中的各种性能指标,如脚本执行时间、渲染时间、重绘和回流次数等。
2.利用Lighthouse工具,它可以对网页进行全面的性能评估,包括加载性能、可访问性、最佳实践等方面,并给出优化建议
3.在代码中手动插入性能测量点,例如使用console.time和console.timeEnd来测量特定代码块的执行时间。
场景题
⽤⼾访问⻚⾯⽩屏了, 原因是啥, 如何排查?
⽹络问题
⽤⼾的⽹络连接可能存在问题,⽆法正确加载⻚⾯内容。可以要求⽤⼾检查⽹络连接, 或者⾃⼰尝试在不同⽹络环境下测试⻚⾯的加载情况。
服务端问题
服务器未正确响应⽤⼾请求,导致⻚⾯⽆法加载。可以检查服务器的状态、⽇志和错 误信息,查看是否有任何异常。同时,可以确认服务器上的相关服务是否正常运⾏。
前端代码问题
⻚⾯的前端代码可能存在错误或异常,导致⻚⾯⽆法正常渲染。可以检查浏览器的 开发者⼯具,查看是否有任何错误信息或警告。同时,可以尝试将⻚⾯的JavaScript、CSS和 HTML代码分离出来进⾏单独测试,以确定具体的问题所在。
浏览器兼容性问题
不同浏览器对于某些代码的⽀持可能不⼀致,导致⻚⾯在某些浏览器中⽆法正 常加载。可以尝试在不同浏览器中测试⻚⾯的加载情况,同时使⽤浏览器的开发者⼯具检查是否有任何错误或警告
第三⽅资源加载问题
⻚⾯可能依赖于某些第三⽅资源(如外部脚本、样式表等),如果这些资源⽆法加载,可能导致⻚⾯⽩屏。可以检查⽹络请求是否正常,是否有任何资源加载失败的情况。
缓存问题
浏览器可能在缓存中保存了旧版本的⻚⾯或资源,导致新版本⽆法加载。可以尝试清除 浏览器缓存,或者通过添加随机参数或修改⽂件名的⽅式强制浏览器重新加载⻚⾯和资源。
其他可能原因
还可能由于安全策略(如CSP、CORS等)限制、跨域问题、DNS解析问题等引起。可以使⽤浏览器的开发者⼯具检查⽹络请求和错误信息,查找可能的问题。
在排查问题时,可以根据具体情况逐步进⾏排查,并结合浏览器的开发者⼯具、服务器⽇志等⼯具来辅助定位问题所在,并且可以与⽤⼾进⾏进⼀步沟通以获取更多信息。如果问题⽆法解决,可以寻求专业的技术⽀持或咨询。
1. js超过Number最大值的数怎么处理?
背景
一般会在大数据的计算;格式展示;用户输入中出现
解决方案
第三方库
decimal.js
const bb = new Decimal('1e+999')
big.js
BigInt
const bigNum = 9007199254740993n; // 注意:数字后⾯添加了 'n' 后缀
注意,BigInt 类型是 ECMAScript 2020 新增的特性,因此在某些浏览器中可能不被⽀持。
格式化成易读的
100000000 -》1亿
表单校验,限制大小
2.说说大文件上传
背景
网络端开了,之前传的没了;网络波动,结果什么都没了;关机了,想接着传做不到
方案
1.前端切片,chunk ,每片500kb,发送到服务器携带⼀个标志,暂时⽤当前的时间戳,⽤于标识⼀个完整的⽂件; 2.服务端保存各段⽂件; 3.浏览器端所有分⽚上传完成,发送给服务端⼀个合并⽂件的请求; 4.服务端根据⽂件标识、类型、各分⽚顺序进⾏⽂件合并; 5.删除分⽚⽂件
注意
--前端切片:主线程做卡顿,web-worker多线程切片,处理完之后交给主进程发送。
--切完后,将blob存储到indexedDB,下次用户进来之后,嗅探一下是否存在未完成上传的切片,有就尝试继续上传。
--websocket,实时通知和请求序列的控制。
代码
const CHUNCK_SIZE = 5*1024*1024'; //每块大小为5MB function uploadFile(){ const file = document.getElementById('fileInput').files[0]; if(!file){ alert('Please select a file.'); } const tatalChuncks = Math.ceil(file.size / CHUNK_SIZE); let currrentChunk = 0; function uploadChunck(){ if(currentChunck >= totalChunks){ console.log('upload complete'); return; } const start = currentChunck *CHUNK_SIZE; const end = Math.min(start + CHUNK_SIZE,file.size); const chunk = file.silce(start,end); const formData = new FormData(): formData.append('file',chunk); formData.append('chunkNumber',currentChunk+1); formData.append('totalChunks',totalChunks); fetch('/upload',{ method:'POST'; body:formData }).then(response => { if(response.ok){ curentChunk++; uploadChunk(); }else{console.error('Chunk upload faild')}; )}.catch( error =>{console.error('Upload error',error)} ); uploadChunk(): }
3.在前端怎么实现网页截图
背景
1.飞书文档,内容在列表页想要查看
2.要把内容导出为png
方案
1.第三方库html2canvas 原理就是canvas
function takeScreenshot(){ const element = document.getElementById('screenshot-target'); html2canvas(element).then(canvas => { const img = canvas.toDataUrl('image/png'); const link = document.createElement('a'); link.ref = img; link.download = 'screenshot.png'; link.click(); }); }
2.dom-to-image插件
先把 DOM 转换为 SVG 然后再把 SVG 转换为图片。
思路
1. ⾸先在页⾯中创建⼀个 Canvas 元素,并设置其宽⾼和样式。
2. 使⽤ Canvas API 在 Canvas 上绘制需要截图的内容,如页⾯的某个区域、某个元素、图⽚等。
3. 调⽤ Canvas API 中的 toDataURL() ⽅法将 Canvas 转化为 base64 编码的图⽚数据。
4. 将 base64 编码的图⽚数据传递给后端进⾏处理或者直接在前端进⾏显⽰。
前端生成海报图怎么做?
第一:html2canvas 开源库
这种方案是通过读取页面DOM元素的信息,然后把dom重新绘制成canvas实现网页截图
优点是支持多种排版样式,有提供跨域问题解决方案,还可以对指定DOM过滤,兼容性更好。缺点是库的体积比较大,计算耗时长,性能比较一般,而且一些属性不支持转化:如不支持伪类,border不支持dash,不支持text-shadow
第二:dom-to-image 开源库
这种方案简单来说就是先把DOM转换为SVG然后再把SVG转换为图片。
优点是体积小,元素齐全,还原度高,缺点是需要自己解决跨域问题,safari不兼容,而且已经没有维护更新了。
第三:canvas 原生绘制
优点是性能比较好,因为用了原生api,不需要考虑兼容性等问题。缺点是需要自己手动写功能,样式排版啥的也要自己处理,还要解决跨域问题。
综上
如果要处理的页面比较复杂,或者需要支持SVG图片渲染,建议选择html2canvas
如果需要稳定的文字、图片渲染能力或者处理结构化数据的能力,建议选择dom-to-image
如果页面基本是图片资源,那么使用原生canvas性能是最好的。
5.使⽤同⼀个链接, 如何实现 PC 打开是 web 应⽤、⼿机打 开是⼀个 H5 应⽤?
可以通过根据请求来源(User-Agent)来判断访问设备的类型,然后在服务器端进⾏适配。
1. js先识别端,再渲染
js : console.log(navigator.userAgent )来判断访问设备的类型
如果是移动设备,可以返回⼀个 H5 ⻚⾯或接⼝数据。
如果是 PC 设备,可以返回⼀个 web 应⽤⻚⾯或接⼝数据。
2. 响应式:媒体查询;flex等
7.设计⼀套全站请求耗时统计⼯具
背景
可以清晰看到整个站点性能情况,首屏加载时间(FP/FCP)
1.监控请求耗时:http/中间件/axios
2.前端监控:整个请求,记录耗时
3.后端监控:后端监控
记录接口开始时间,结束时间
4.数据汇总:数据可视化
方案
Performance API
是浏览器提供的⼀组 API,可以⽤于测量⽹⻚性能。可以获取⻚⾯各个阶段的时间、资源加载时间等
fetch上报
创建一个图片,src带上一些参数,后端就能接收到
⾃定义封装的请求函数
可以⾃⼰封装⼀个请求函数,在请求开始和结束时记录时间,从⽽计算请求耗时。
8.如何修改第三方库
稳定的库,直接扒下来,在 node_modules 中进行修改
patch 方案:适合简单的
fork package,自己维护
直接修改源码,改完后构建,发部到 npm 私服
9. 当QPS达到峰值
当每秒查询次数达到峰值,会对服务器和应用造成很大的压力,甚至系统崩溃
方案
1.请求限流
后端处理
2.请求合并
短时间内的请求进行合并,一次性降低服务器压力
3.请求缓存
如果没有改变,直接命中
4.任务队列
10.如何实现⽹页加载进度条?
思路
拿到进度
绘制进度
方案
1. ajax 拿到进度,svg/dom绘制进度
2. 页面加载
监听页面加载进度,设置定时器不断把宽度加宽
3. 库:react - > nprogress
4. vue : 通过导航守卫
11. 前端⽔印了解多少?
明⽔印
明⽔印是通过在⽂本或图像上覆盖另⼀层图像或⽂字来实现的。这种⽔印会明显地出现在⻚⾯上,可以⽤来显⽰版权信息或其他相关信息。
方案
1. 背景图:svg + canvas
创建svg,动态生产 body.stylebackgroundImage
2.图片水印
使用canvas
3. 重复的dom元素覆盖实现
暗⽔印
将待嵌⼊的信息经过处理和加密后,转化为⼆进制数据
后端做
定期检查水印元素
如果水印是一个 DOM 节点,可以使用 MutationObserver 定期监控水印节点。如果发现其被删除,则可重新添加
代码
const watermark = document.createElement('div'); watermark.innerText = '水印'; watermark.style.position = 'fixed'; watermark.style.opacity = '0.1'; document.body.appendChild(watermark); // 创建观察者实例 const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.removedNodes.length > 0) { mutation.removedNodes.forEach((node) => { if (node === watermark) { console.log('水印已被删除,正在重建...'); document.body.appendChild(watermark); } }); } }); }); // 配置并开始观察 observer.observe(document.body, { childList: true, subtree: true });
12. web 应⽤中如何对静态资源加载失败的场景做降级处理
图片
1.站位图,alt描述
2.重试机制,是404,还是无权限
3.上报错误
概要
css文件
1.关键性样式内联
2.备用样式
3.上报
概要
js文件
1.内联脚本
2.备用脚本
3.上报
概要
CDN
1.本地备份,如果CDN错误,就使用本地
2.动态切换,切到另一个CDN上
概要
字体
1.使用降级字体: apple/微软雅黑
2.webfont
概要
ssr
1.使用降级html
2.切换到CSR (客户端渲染)
13. 函数式编程了解多少?
函数是一等公民,函数的封装方式解决问题
核⼼概念
1.纯函数
有输入有输出
2.不可逆性
3.高阶函数,函数柯里化
⾼阶函数是指可以接收其他函数作为参数,也可以返回函数的函数
柯里化:把接受多个参数的函数,转换为接受单一参数的函数,而且返回接收的剩余参数,还有返回结果的新参数
4.函数组合
函数可以组合成复杂的函数,从⽽减少重复代码的产⽣。
优势
易于理解和维护
更少的 bug
更好的可测试性
更少的重构
避免并发问题
代码复⽤
14.电影票的选座功能
使用canvas来实现
思路:
15.移动端如何实现上拉加载,下拉刷新?
长列表中,通过上拉加载提升性能
思路
1.滚动事件监听
2.判断触底
3.回调加载更多
下拉刷新
1.监听触摸事件
2.显示刷新指示器,判断有没有达到下拉阈值
3.触发刷新操作
注意
1.性能优化方面一定要有节流防抖
2.用户体验:要有下拉刷新提示;错误处理;动画效果
3.兼容:触摸事件的兼容;css的兼容
16.深度 SEO 优化的⽅式有哪些 搜索引擎优化
结构优化
1.标签语义化,但是实际上很难,因为大部分都是div走天下
2.内容优化:描述信息,关键字
技术方面
3.站点地图
告诉用户哪些可以爬重
4.结构化数据:添加script强行加戏
5.移动端兼容
媒体查询
17.⼀直在 window 上⾯挂东西是否有什么风险
⻛险
1. 命名冲突
多人开发 window.hellow = '111',别人可能也会这样命名
2. 安全漏洞
自己的方法,别人也会操作
3. 代码维护性
4.性能问题,增加内存开销
措施
1. 使⽤模块化开发
将代码模块化,避免对全局 window 对象的直接依赖。使⽤模块加载器(如ESModules、CommonJS、AMD)来管理模块之间的依赖关系,以减少全局命名冲突和代码冗余。
2. 使⽤严格模式
在JavaScript代码中使⽤严格模式( "use strict" ),以启⽤更严格的语法检 查和错误处理。严格模式可以帮助捕获潜在的错误和不安全的⾏为。
3.显式访问全局对象
如果确实需要访问全局 window 对象的属性或⽅法,请使⽤显式访问⽅式, 如 window.localStorage 、 window.setTimeout() 等。避免直接引⽤全局属性,以减少 冲突和误⽤的⻛险
4.谨慎处理第三⽅代码
在使⽤第三⽅库或框架时,注意审查其对全局 window 对象的使⽤⽅式。 确保库或框架的操作不会产⽣潜在的安全⻛险或全局命名冲突。
18.实现一个无限级目录树:后台管理系统的菜单
数据:name+children,如果没有需要改造数据
先创建一个父级元素 ul; for循环得到一级目录; 然后判断是否有子级children ,递归遍历 如果父级不存在,就把他添加到顶级元素中
19.延迟加载js
script的属性(defer/async); 动态创建script; setTimeout; js脚本在最下面
站点⼀键换肤的实现⽅式有哪些?
使⽤ CSS 变量
通过定义⼀些变量来控制颜⾊、字体等,然后在切换主题时动态修改这些变量的 值
使⽤ class 切换
在 HTML 的根元素上添加不同的 class 名称,每个 class 名称对应不同的主题样 式,在切换主题时切换根元素的 class 名称即可。
使⽤ JavaScript 切换
使⽤ JavaScript 动态修改⻚⾯的样式,如修改元素的背景颜⾊、字体颜⾊ 等
使⽤ Less/Sass 等 CSS 预处理器
通过预处理器提供的变量、函数等功能来实现主题切换。
常见图⽚懒加载⽅式有哪些?
Intersection Observer API:检测图⽚是否已经进⼊视⼝,并根据需要进⾏相应的处理。
let observer = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting) { const lazyImage = entry.target; lazyImage.src = lazyImage.dataset.src; observer.unobserve(lazyImage); } }); }); const lazyImages = [...document.querySelectorAll(".lazy")]; lazyImages.forEach(function (image) { observer.observe(image); });
⾃定义监听器:img.offsetTop < window.innerHeight + scrollTop
function lazyLoad() { const images = document.querySelectorAll(".lazy"); const scrollTop = window.pageYOffset; images.forEach((img) => { if (img.offsetTop < window.innerHeight + scrollTop) { img.src = img.dataset.src; img.classList.remove("lazy"); } }); } let lazyLoadThrottleTimeout; document.addEventListener("scroll", function () { if (lazyLoadThrottleTimeout) { clearTimeout(lazyLoadThrottleTimeout); } lazyLoadThrottleTimeout = setTimeout(lazyLoad, 20); });
⼩程序为什么会有两个线程
是为了提⾼渲染速度、避免阻塞和资源隔离。 渲染线程负责界⾯渲染,逻辑线程负责业务逻辑和数据处理,两者通过微信客⼾端进⾏通信和交互,共同实现⼩程序的功能和性能。
渲染线程(UI 线程)
负责⼩程序界⾯的渲染和响应⽤⼾的交互。它使⽤ WebView 进⾏⻚⾯渲染,包括解析和绘制 DOM、布局、样式计算和渲染等操作。渲染线程是单线程的,所有的界⾯操作都在这个线程中进⾏。
逻辑线程(JS 线程)
负责⼩程序的逻辑运算和数据处理。它是基于 JavaScript 运⾏的,负责处理⽤⼾交互、业 务逻辑、数据请求、事件处理等操作。逻辑线程是独⽴于渲染线程的,可以并⾏处理多个任务,避免阻塞界⾯的渲染和响应。
好处
• 响应速度:逻辑线程和渲染线程分开,可以并⾏执⾏,提⾼了⼩程序的响应速度和⽤⼾体验 • 防⽌阻塞:逻辑线程的运⾏不会阻塞渲染线程,避免了⻓时间的计算或数据处理导致界⾯卡顿或⽆响应的情况。 • 资源隔离:渲染线程和逻辑线程是独⽴的,它们有各⾃的资源和运⾏环境,可以避免相互⼲扰和影响。
前端有哪些跨页⾯通信⽅式?
使⽤URL参数
可以通过URL参数在不同⻚⾯之间传递数据。例如,可以在URL中添加查询字符串 参数来传递数据,并通过解析URL参数来获取传递的数据。
使⽤localStorage或sessionStorage
⼀个⻚⾯可以将数据存储在本地存储中,另⼀个⻚⾯ 可以读取该数据。
使⽤Cookies
可以使⽤Cookies在不同⻚⾯之间共享数据。⼀个⻚⾯可以将数据存储在Cookie 中,另⼀个⻚⾯可以读取该Cookie。
使⽤postMessage API
postMessage API允许不同窗⼝或iframe之间进⾏跨⻚⾯通信。可以使⽤ postMessage发送消息,接收⽅可以通过监听message事件来接收消息。
使⽤Broadcast Channel API
Broadcast Channel API允许不同⻚⾯或不同浏览器标签之间进⾏⼴播式的消息传递。可以使⽤Broadcast Channel发送消息,其他订阅同⼀频道的⻚⾯都可以接收到消息。
使⽤Shared Worker
使⽤Shared Worker:Shared Worker是⼀种特殊的Web Worker,可以在多个⻚⾯之间共享。可 以通过Shared Worker进⾏通信和共享数据。
使⽤WebSocket
WebSocket是⼀种双向通信协议,可以在不同⻚⾯之间建⽴持久的连接,实现 实时的跨⻚⾯通信。
扫码登录实现⽅式
扫码登录的实现原理核⼼是基于⼀个中转站,该中转站通常由应⽤提供商提供,⽤于维护⼿机和PC之 间的会话状态。
1.⽤⼾在PC端访问应⽤,并选择使⽤扫码登录⽅式。此时,应⽤⽣成⼀个随机的认证码,并将该认证码通过⼆维码的形式显⽰在PC端的⻚⾯上。
2. ⽤⼾打开⼿机上的应⽤,并选择使⽤扫码登录⽅式。此时,应⽤会打开⼿机端的相机,⽤⼾可以对着PC端的⼆维码进⾏扫描。
3. ⼀旦⽤⼾扫描了⼆维码,⼿机上的应⽤会向应⽤提供商的中转站发送⼀个请求,请求包含之前⽣成的随机认证码和⼿机端的⼀个会话ID。
4. 中转站验证认证码和会话ID是否匹配,如果匹配成功,则该中转站将⽤⼾的⾝份信息发送给应⽤,并创建⼀个PC端和⼿机端之间的会话状态。
5. 应⽤使⽤收到的⾝份信息对⽤⼾进⾏认证,并创建⼀个与该⽤⼾关联的会话状态。同时,应⽤返回⼀个通过认证的响应给中转站。
6. 中转站将该响应返回给⼿机端的应⽤,并携带⼀个⽤于表⽰该会话的令牌,此时⼿机和PC之间的认证流程就完成了。
7. 当⽤⼾在PC端进⾏其他操作时,应⽤将会话令牌附加在请求中,并通过中转站向⼿机端的应⽤发起请求。⼿机端的应⽤使⽤会话令牌(也就是之前⽣成的令牌)来识别并验证会话状态,从⽽允许⽤⼾在PC端进⾏需要登录的操作。
vue-cli 都做了哪些事⼉,有哪些功能?
Vue CLI 是⼀个基于 Vue.js 的命令⾏⼯具,⽤于快速搭建、开发和构建 Vue.js 项⽬。它提供了⼀系列的功能来简化 Vue.js 项⽬的开发和部署流程,包括:
1. 项⽬脚⼿架:Vue CLI 可以通过简单的命令⾏交互⽅式快速⽣成⼀个新的 Vue.js 项⽬的基础结构, 包括⽬录结构、配置⽂件、⽰例代码等。
2. 开发服务器:Vue CLI 提供了⼀个开发服务器,⽤于在本地运⾏项⽬,在开发过程中实时预览和调试应⽤程序。它⽀持热模块替换(HMR),可以实时更新⻚⾯内容,提⾼开发效率。
3. 集成构建⼯具:Vue CLI 集成了 Webpack,可以⾃动配置和管理项⽬的构建过程。它通过配置⽂件可以进⾏定制,例如设置打包输出路径、优化代码、压缩资源等。
4. 插件系统:Vue CLI 提供了丰富的插件系统,可以通过安装插件来扩展项⽬的功能。这些插件可以帮助处理样式、路由、状态管理、国际化等⽅⾯的需求,提供更多的开发⼯具和功能⽀持。
5. 测试集成:Vue CLI 集成了测试⼯具,可以快速配置和运⾏单元测试和端到端测试。它⽀持多种测试框架,如 Jest、Mocha、Cypress 等,可以帮助开发⼈员编写和运⾏各种类型的测试。
6. 项⽬部署:Vue CLI 提供了命令⾏接⼝,可以⽅便地将项⽬部署到不同的环境,如开发环境、测试环境和⽣产环境。它⽀持⽣成优化过的静态⽂件、⾃动压缩和缓存等功能。
站点如何防⽌爬⾍?
1. 修改 robots.txt
在站点的根⽬录下创建或修改 robots.txt ⽂件,⽤来告知遵守该协议的爬⾍应该爬取哪些⻚⾯, 哪些不应该爬取。
2. 使⽤ CAPTCHA
对于表单提交、登录⻚⾯等,使⽤验证码(CAPTCHA)可以防⽌⾃动化脚本或机器⼈执⾏操作
3. 检查⽤⼾代理字符串
服务器可以根据请求的⽤⼾代理(User-Agent)字符串来决定是否屏蔽某些爬⾍。但⽤⼾代理字符串可以伪造,所以这不是⼀个完全可靠的⽅法。
4. 分析流量⾏为
分析访问者的⾏为,⽐如访问频率、访问⻚数、访问时⻓,并与正常⽤⼾的⾏为进⾏对⽐,从⽽尝试检测和屏蔽爬⾍。
在表单校验场景中, 如何实现⻚⾯视⼝滚动到报错的位置
为了提⾼⽤⼾体验,可以将⻚⾯滚动⾄对应表单报错的位置,使得⽤⼾⽴即可⻅错误并进⾏修 改。这通常可以通过 JavaScript 编程实现。
1. 记录表单元素的位置:在表单提交前的适当时间⾥记录所有表单元素的错误位置。
2. 滚动到特定错误:错误发⽣时,滚动到第⼀个错误的表单元素位置。
3. 优化:可为同⼀元素多次错误滚动优化,避免不必要的⽤⼾⼲扰。
应⽤上线后, 怎么通知⽤⼾刷新当前⻚⾯?
如何去感知前端静态资源已经发⽣了更新?
⾸先要做静态资源版本管理。 这个版本直接给到 html 模板即可, 其他 link 打包的资源还是以哈希code 作为⽂件名称后缀。
如何主动推送给客⼾端
这个实现⽅式就⾮常的多了,我这⾥建议让服务端来做处理
因为我们前端静态资源打包之后, ⼤多数会上传到云存储服务器上, 或者甚⾄是 服务器本地 也⾏。这个时候, 后端给⼀个定时任务, ⽐如 1 分钟去执⾏⼀次, 看看是否有新的 html 版本的内容⽣成。如果有新的 html 版本内容⽣成, 且当前⽤⼾访问的还是旧版本, 那么直接发⼀个服务端信息推送即可(SSE 允许服务器推送数据到浏览器)。这样做成本是最低的, 甚⾄可以说是⼀劳永逸。 前端是没有任何负债, 没有任何性能问题。
WebSockets
通过 WebSocket 连接,服务器可以实时地向客⼾端发送消息,包括静态资源更新的通知。收到消息后,客⼾端可以采取相应的措施,⽐如显⽰⼀个提⽰信息让⽤⼾选择是否重新加载⻚⾯。
Service Workers(推荐
Service workers 位于浏览器和⽹络之间,可以控制⻚⾯的资源缓存。它们也可⽤于检测资源更新,当检测到静态资源更新时,可以通过推送通知或在⽹站上显⽰更新提⽰。
轮询
客⼾端⽤ JavaScript 定时发送 HTTP 请求到服务器,查询版本信息。如果检测到新版本,可以提醒⽤⼾或⾃动刷新资源。
如何检测⽹⻚空闲状态(⼀定时间内⽆操作)
⽤⼾操作⽹⻚,⽆⾮就是通过 ⿏标 、 键盘 两个输⼊设备(暂不考虑⼿柄等设备)。因⽽我们可以监听相应的输⼊事件,来判断⽹⻚是否空闲(⽤⼾是否有操作⽹⻚)。 1. 监听⿏标移动事件 mousemove ; 2. 监听键盘按下事件 mousedown ; 3. 在⽤⼾进⼊⽹⻚后,设置延时跳转,如果触发以上事件,则移除延时器,并重新开始。
如何禁⽌别⼈调试⾃⼰的前端⻚⾯代码?
⽆限 debugger
(() => { function ban() { setInterval(() => { debugger; }, 50); }try { ban(); } catch (err) { } })();
后端⼀次性返回树形结构数据,数据量⾮常⼤, 前端该如何 处理?
导致前端⼀次性计算和渲染会栈溢出的情况
1. 分批处理
将⼤量的树形数据分为多个批次进⾏处理和渲染。前端可以通过递归或循环的⽅式,每次处理⼀部分数据,并在渲染完成后再处理下⼀部分数据。这样可以避免⼀次性处理⼤量数据造成栈溢出的问题。
2. 异步处理
使⽤异步处理的⽅式进⾏数据的计算和渲染。前端可以利⽤JavaScript的异步特性,将数据处理和渲染任务分为多个异步任务,并通过事件循环机制依次执⾏这些任务。这样可以避免⼀次性计算和渲染⼤量数据导致栈溢出的问题。
3. 虚拟化渲染
使⽤虚拟化渲染技术,只渲染当前可⻅区域的树节点,⽽不是全部节点。可以根据⻚⾯的滚动位置和⽤⼾操作,只渲染当前需要展⽰的节点,⽽对于不可⻅的节点只保留其占位符。这样可以减少实际渲染的节点数量,降低内存占⽤和渲染时间。
4. 数据分级处理
对于树形结构数据,可以考虑对数据进⾏分级处理。将数据根据节点的层级关系进⾏分组,每次只处理和渲染当前层级的节点数据。这样可以减少每次处理的数据量,降低栈溢出的⻛险。
你认为组件封装的⼀些基本准则是什么
1. 单⼀职责原则:⼀个组件应该具有单⼀的功能,并且只负责完成该功能,避免组件过于庞⼤和复杂。
2. ⾼内聚低耦合:组件内部的各个部分之间应该紧密相关,组件与其他组件之间应该尽量解耦,减少 对外部的依赖。
3. 易⽤性:组件应该易于使⽤,提供清晰的接⼝和⽂档,使⽤⼾能够⽅便地使⽤组件。
4. 可扩展性:组件应该具有良好的扩展性,能够⽅便地添加新的功能或进⾏修改,同时不影响已有的 功能。
5. 可重⽤性:组件应该是可重⽤的,能够在多个项⽬中使⽤,减少重复开发的⼯作量。
6. ⾼效性:组件应该具有⾼性能和低资源消耗的特点,不会成为整个系统的性能瓶颈。
7. 安全性:组件应该具有安全性,能够防⽌恶意使⽤或攻击。
8. 可测试性:组件应该容易进⾏单元测试和集成测试,以保证组件的质量和稳定性。
前端⽇志埋点 SDK 设计思路 前端监控
为什么需要前端监控
获取用户行为以及跟踪产品在用户端的使用情况,并以监控数据为基础,指明产品优化的方向
一、前端监控可以分为三类
(1)数据监控
顾名思义就是监听用户的行为
1. PV + UV PV(page view),即页面浏览量或点击量。用户每次对网站的访问均会被记录为一次PV,每刷新一次网站也会被记录一次PV UV:是独立访问用户数,表示一段时间内,访问某网站的独立IP地址,如果一个用户多次访问了网站,则只会被计算成一次UV,多次刷新页面,也只会被计算成一次UV。 2. 用户在每一个页面的停留时间 3. 用户通过什么入口来访问该网页 4. 用户在相应的页面中触发的行为
统计这些数据是有意义的,比如我们知道了用户来源的渠道,可以促进产品的推广,知道用户在每一个页面停留的时间,可以针对停留较长的页面,增加广告推送等等。
(2)性能监控
监听前端的性能,主要包括监听网页或者说产品在用户端的体验。
1. 不同用户,不同机型和不同系统下的首屏加载时间
2. 白屏时间
3. http等请求的响应时间
4. 静态资源整体下载时间
5. 页面渲染时间
6. 页面交互动画完成时间
这些性能监控的结果,可以展示前端性能的好坏,根据性能监测的结果可以进一步的去优化前端性能,比如兼容低版本浏览器的动画效果,加快首屏加载等等。
(3)异常监控
产品的前端代码在执行过程中也会发生异常,因此需要引入异常监控。及时的上报异常情况,可以避免线上故障的发上。虽然大部分异常可以通过try catch的方式捕获,但是比如内存泄漏以及其他偶现的异常难以捕获
1. 资源加载错误
2. Javascript错误
3. promise asybc await 错误
二、实现前端监控的步骤为
前端埋点和上报、数据处理和数据分析
前端埋点方法分为三种
(1) 代码埋点
就是以嵌入代码的形式进行埋点,比如需要监控用户的点击事件,会选择在用户点击时,插入一段代码,保存这个监听行为或者直接将监听行为以某一种数据格式直接传递给server端。此外比如需要统计产品的PV和UV的时候,需要在网页的初始化时,发送用户的访问信息等。
优点
可以在任意时刻,精确的发送或保存所需要的数据信息
缺点
工作量较大,每一个组件的埋点都需要添加相应的代码
(2)可视化埋点
通过可视化交互的手段,代替代码埋点。将业务代码和埋点代码分离,提供一个可视化交互的页面,输入为业务代码,通过这个可视化系统,可以在业务代码中自定义的增加埋点事件等等,最后输出的代码耦合了业务代码和埋点代码。
可视化埋点听起来比较高大上,实际上跟代码埋点还是区别不大。也就是用一个系统来实现手动插入代码埋点的过程。
缺点
可视化埋点可以埋点的控件有限,不能手动定制。
(3)无埋点
无埋点并不是说不需要埋点,而是全部埋点,前端的任意一个事件都被绑定一个标识,所有的事件都别记录下来。通过定期上传记录文件,配合文件解析,解析出来我们想要的数据,并生成可视化报告供专业人员分析因此实现“无埋点”统计。
从语言层面实现无埋点也很简单,比如从页面的js代码中,找出dom上被绑定的事件,然后进行全埋点。
优点
由于采集的是全量数据,所以产品迭代过程中是不需要关注埋点逻辑的,也不会出现漏埋、误埋等现象
缺点
无埋点采集全量数据,给数据传输和服务器增加压力
无法灵活的定制各个事件所需要上传的数据
三、定制我们的埋点和上报方案
(1)监控数据
首先我们需要明确一个产品或者网页,普遍需要监控和上报的数据。 监控的分为三个阶段:用户进入网页首页、用户在网页内部交互和交互中报错。
(2)埋点方案
在实际项目中考虑到上报数据的灵活定制,以及减少数据传输和服务器的压力,在所需埋点处不多的情况下,常用的方式是代码埋点。 以用户进入首页为例,我们在首页渲染完成后会发送事件类型和类型相关的数据给server端,告知首页的监控信息。
• 发送埋点信息的时候, 不影响性能, 不阻碍⻚⾯主流程加载和请求发送。
(3)上报周期和上报数据类型
如果埋点的事件不是很多,上报可以时时进行,比如监控用户的交互事件,可以在用户触发事件后,立刻上报用户所触发的事件类型。 如果埋点的事件较多,或者说网页内部交互频繁,可以通过本地存储的方式先缓存上报信息,然后定期上报。
上报方法
ajax
缺点是可能会存在跨域风险,当页面销毁时的监控埋点大概率会上报失败。
image gif
前端通过创建一个Image对象,将要上报的数据作为URL参数拼接到一个1x1像素的透明图片src属性中实现数据上报。目前有挺多公司会采用这种方案
优点是没有跨域问题,兼容性好,速度快,不会阻塞页面加载和关闭。 缺点是只能发送get请求,不支持异步操作。
Navigator.sendBeacon
这是目前通用的埋点上报方案。sendBeacon是w3c新引入的补充性api,可以用来解决web页面在触发卸载销毁事件期间会中断所有异步xhr请求的问题。可以接收两个参数,第一个是目标服务器的 URL,第二个是要发送的数据。
优点是,页面销毁时埋点数据也可以正常发送,不会阻塞页面关闭。缺点是只支持post请求,而且因为是新补充的api,会存在浏览器兼容性问题。
基于WebSocket
这种方案目前不常用。通过WebSocket协议与服务器建立持久连接,并通过发送消息来进行实时的埋点数据上报。 优点是实时性好,支持双向通信。 缺点是需要服务端支持WebSocket协议,实现方案复杂,不适用简单的埋点需求。
所以,如果是上报轻量级的数据,可以使用基于img方案,如果需要大量级的数据且有很多自定义数据,可以使用基于ajax或者基于WebSocket方案,如果需要在用户关闭浏览器时上报数据,可以使用sendBeacon,但是需要增加判断,如果浏览器不支持sendBeacon,需要降级为img方案。
上报时机
setTimeout
beforeUnload
缓存批量
上报的数据
确定需要埋点上报的数据,上报的信息包括用户个人信息以及用户行为,主要数据可以分为: who: appid(系统或者应用的id),userAgent(用户的系统、网络等信息) when: timestamp(上报的时间戳) from where: currentUrl(用户当前url),fromUrl(从哪一个页面跳转到当前页面),type(上报的事件类型),element(触发上报事件的元素) what: 上报的自定义扩展数据data:{},扩展数据中可以按需求定制,比如包含uid等信息
四、前端监控结果可视化展示系统的设计
当后端得到前端上报的信息之后,经过数据分析和处理,需要前端可视化的展示数据分析后的结果。
单个用户
在交互过程中触发各个埋点事件的次数
在某个时间周期内,访问本网页的入口来源
在每一个子页面的停留时间
全体用户
某一个时间段内网页的PV和UV
全体用户访问网页的设备和操作系统分析
某一个时间段内访问本网页的入口来源分析
全体用户在访问本网页时,在交互过程中触发各个埋点事件的总次数
全体用户在访问本网页时,网页上报异常的集合
删选功能集合
时间筛选:提供今日(00点到当前时间)、本周、本月和全年
用户删选:提供根据用户id删选出用户行为的统计信息
设备删选:删选不同系统的整体展示信息
在前端应⽤如何进⾏权限设计?
⻆⾊与权限分离
将⽤⼾的权限分为不同的⻆⾊,每个⻆⾊拥有特定的权限。
只需要调整⻆⾊的权限,⽽不需要逐个修改⽤⼾的权 限。
功能级权限控制
对于敏感操作或者需要权限控制的功能,需要在前端实现功能级的权限控制。
通过在代码中判断⽤⼾是否拥有执⾏该功能的权限,来决定是否展⽰或者禁⽤相关功能。
功能级权限控制是指在系统中对⽤⼾进⾏细粒度的权限控制,即控制⽤⼾是否能够执⾏某个具体的功 能或操作
路由级权限控制
对于不同的⻚⾯或路由,可以根据⽤⼾的⻆⾊或权限来进⾏权限控制。在前端路由中配置权限信息,当⽤⼾访问特定路由时,前端会检查⽤⼾是否具备访问该路由的权限。
动态权限管理
在前端应⽤中,可以实现动态权限管理,即在⽤⼾登录时从服务器获取⽤⼾的权限信息,并在前端进⾏缓存。这样可以保证⽤⼾权限的实时性,同时也便于后端对权限进⾏调整和管理。
UI级的权限控制
对于某些敏感信息或操作,可以通过前端的界⾯设计来进⾏权限控制。例如,隐藏某些敏感字段或操作按钮,只对具有相应权限的⽤⼾可⻅或可操作。
异常处理与安全验证
在前端应⽤中,需要实现异常处理机制,当⽤⼾越权操作时,需要给予相应提⽰并记录⽇志。同时,对于敏感操作,需要进⾏⼆次验证,例如通过输⼊密码或短信验证码等⽅式进⾏安全验证。
echarts大量数据性能优化处理
会出现:渲染卡顿
1. 关闭动画:直接关闭;或者超过一定的值再关闭
ECharts默认的动画效果会消耗一些性能,对于大数据量的图表,可以尝试关闭动画。 在数据量特别大的时候,为图形应用动画可能会导致应用的卡顿,这个时候我们可以设置animation: false关闭动画。 对于数据量会动态变化的图表,我们更推荐使用animationThreshold这个配置项,当画布中图形数量超过这个阈值的时候,ECharts 会自动关闭动画来提升绘制性能。这个配置往往是一个经验值,通常 ECharts 的性能足够实时渲染上千个图形的动画(我们默认值也是给了 2000),但是如果你的图表很复杂,或者你的用户环境比较恶劣,页面中又同时会运行很多其它复杂的代码,也可以适当的下调这个值保证整个应用的流畅性。
let option = { animation: false, series: [ // ... ] }; echarts.setOption(option);
2. 使用 large 模式
当数据量特别大(如超过千条数据)时,此模式下会对绘制进行优化。
let option = { series: [ { type: 'scatter', large: true, data: largeData, }, ], }; echarts.setOption(option);
3. 启用进度渲染
在数据量大于 progressiveThreshold 时,图表会启用渐进渲染。 对于特别大的数据集,可以让用户知道渲染的进度,同时也可以避免浏览器在渲染过程中出现无响应的现象
let option = { series: [{ type: 'lines', data: largeData, // 开启渐进式渲染 progressive: 2000, // 渲染阈值,大于此值则启动渐进渲染 progressiveThreshold: 5000, }], }; echarts.setOption(option);
4. 增加滑动轴和懒加载
这种方法能够很好展示部分区间的数据,但是缺点也很明显,很难看到全局的数据,而且要重复的请求和监听,这对于大屏来说无疑不太合适
const option = { ... dataZoom: [ { type: 'slider', xAxisIndex: 0, filterMode: 'none' } ] ... } myChart.on('dataZoom', function (params) { ... }
5. 数据降维或者降采样
折线图在数据量远大于像素点时候的降采样策略,全部绘制不过滤数据点。
var option = { series: { type: "line", sampling: "lttb", // 最大程度保证采样后线条的趋势,形状和极值。 }, }; 'lttb' 采用 Largest-Triangle-Three-Bucket 算法,可以最大程度保证采样后线条的趋势,形状和极值。 'average' 取过滤点的平均值 'min' 取过滤点的最小值 'max' 取过滤点的最大值 'minmax' 取过滤点绝对值的最大极值 (从 v5.5.0 开始支持) 'sum' 取过滤点的和
优点: 1. 使用简单,ECharts 内部降采样算法,效果显著 2. 可以完整的将曲线趋势展示出来,和原曲线基本一致 缺点: 1. 并不是展示的所有点,会删除一些无用的点,保证渲染性能 2. 最大程度保证采样后线条的趋势,形状和极值,但是某些情况下,极值有偏差,测试中发现
6. 数据进行筛选和抽样来减少渲染点数
简单随机抽样
7.其他
服务器提速
优化数据结构,精简数据返回字段,降低数据包大小
开启 gzip 压缩,加快海量数据下载速度
数据处理
数据聚合:对于特别密集的数据点,使用聚合算法在源头对数据降采样,进行数据聚合,减少渲染的数据点数量。
数据过滤:数据中存在一些无关的信息或数据噪音,服务端对数据进行过滤,只需要保留有用的数据即可,剔除无效的数据。
一次请求大量数据怎么优化,数据多导致渲染慢怎么优化
首先大量数据的接收,那么肯定是用异步的方式进行接收, 对数据进行一个分片处理,可以拆分成一个个的小单元数据,通过自定义的属性进行关联。这样数据分片完成。 接下来渲染的话,由于是大量数据,如果是长列表的话,这里就可以使用虚拟列表(当前页面需要渲染的数据拿到进行渲染,然后对前面一段范围及后面一段范围,监听对应的滚动数据来切换需要渲染的数据,这样始终要渲染的就是三部分)。当然还有别的渲染情况,比如echarts图标大量点位数据优化等。
如何解决页⾯请求接⼝⼤规模并发问题
不仅仅是包含了接⼝并发, 还有前端资源下载的请求并发。
1. 后端优化
对接⼝进⾏优化,采⽤缓存技术,对数据进⾏预处理,减少数据库操作等。使⽤集群技术,将请求分散到不同的服务器上,提⾼并发量。另外可以使⽤反向代理、负载均衡等技术,分担服务器压⼒。
2. 做 BFF 聚合
把所有⾸屏需要依赖的接⼝, 利⽤服务中间层给聚合为⼀个接⼝。
3. CDN加速
使⽤CDN缓存技术可以有效减少服务器请求压⼒,提⾼⽹站访问速度。CDN缓存可以将 接⼝的数据存储在缓存服务器中,减少对原始服务器的访问,加速数据传输速度。
4. 使⽤ WebSocket:
可以建⽴⼀个持久的连接,避免反复连接请求。WebSocket 可以实现双向通信,⼤幅降低服务器响应时间。
5. 使⽤ HTTP2 及其以上版本, 使⽤多路复⽤
6. 使⽤浏览器缓存技术
强缓存、协商缓存、离线缓存、Service Worker 缓存 等⽅向
7. 聚合⼀定量的静态资源
⽐如提取⻚⾯公⽤复⽤部分代码打包到⼀个⽂件⾥⾯、对图⽚进⾏雪碧图 处理, 多个图⽚只下载⼀个图⽚。
8. 采⽤微前端⼯程架构
只是对当前访问⻚⾯的静态资源进⾏下载, ⽽不是下载整站静态资源
9. 使⽤服务端渲染技术
从服务端把⻚⾯⾸屏直接渲染好返回, 就可以避免掉⾸屏需要的数据再做 额外加载和执⾏
JS 执⾏ 100 万个任务, 如何保证浏览器不卡顿?
Web Workers
将这些任务从主线程中分离出来。Web Workers允许在后台线程中运⾏脚本,从⽽避免阻塞主线程,保持⻚⾯的响应性。
// 主线程代码 const worker = new Worker('worker.js'); // 创建一个新的Web Worker worker.postMessage({ start: 0, end: 1000000 }); // 向Web Worker发送消息 worker.onmessage = function(event) { const result = event.data; console.log('任务完成:', result); }; // worker.js - Web Worker代码 onmessage = function(event) { const start = event.data.start; const end = event.data.end; let sum = 0; for (let i = start; i <= end; i++) { sum += i; } postMessage(sum); // 向主线程发送消息 };
任务分割
使⽤ requestAnimationFrame 来实现任务分割是⼀种常⻅的⽅式,它可以确保任务在浏览器的每 ⼀帧之间执⾏,从⽽避免卡顿。
requestAnimationFrame 也是个定时器,不同于 setTimeout ,它的时间不需要我们⼈为指定,这个时间取决于当前电脑的刷新率,如果是 60Hz ,那么就是 16.7ms 执⾏⼀次,如果是 120Hz 那就是 8.3ms 执⾏⼀次,这么⼀来,每次电脑屏幕 16.7ms 后刷新⼀下,定时器就会产⽣ 20 个 li , dom 结构的出现和屏幕的刷新保持了⼀致
const total = 100000; let ul = document.getElementById("container"); let once = 20; let page = total / once; function loop(curTotal) { if (curTotal <= 0) return; let pageCount = Math.min(curTotal, once); window.requestAnimationFrame(() => { // 创建⼀个虚拟⽂档碎⽚ let fragment = document.createDocumentFragment(); for (let i = 0; i < pageCount; i++) { let li = document.createElement("li"); li.innerHTML = ~~(Math.random() * total); fragment.appendChild(li); // 挂到fragment上 } ul.appendChild(fragment); // 现在才回流 loop(curTotal - pageCount); }); } loop(total);
后端一次性给予10万条数据怎么办
需要在性能、用户体验、和浏览器内存限制之间做出权衡。 直接渲染大量数据会导致页面卡顿甚至崩溃
1. 后端分页(最优方案 )
思路: 让后端分页返回数据,前端按需请求,每次只获取一小部分数据。 前端只加载当前页数据,大幅优化性能。
适用场景: 数据适合分页展示,如数据表格、列表等。
2. 虚拟列表(适用于大表格/列表)
思路: 如果必须一次性获取所有数据,使用 虚拟列表 渲染可视范围内的元素,减少 DOM 负担。
适用场景: 需要展示非常大量的数据列表。
使用库: 可以使用现成的库,如 react-window 或 virtual-scroll。
3. 前端懒加载(滚动加载 / 分批渲染)
如果 API 不能分页,可以前端手动分批渲染,避免一次性渲染 10 万条数据。
适用场景: 社交媒体流、长列表。
const [visibleData, setVisibleData] = useState([]); const batchSize = 500; useEffect(() => { let index = 0; const loadMore = () => { if (index >= allData.length) return; setVisibleData((prev) => [...prev, ...allData.slice(index, index + batchSize)]); index += batchSize; requestAnimationFrame(loadMore); }; loadMore(); }, []);
4. 数据分片处理:适合一次性加载但分批渲染
思路: 将数据切分为较小的块逐步渲染,避免一次性渲染导致页面卡顿。
适用场景: 需要一次性加载全部数据,但渲染时避免页面卡死。
5. 使用 Web Worker 处理数据:适合数据量大且需要复杂处理的场景
思路: 在后台线程使用 Web Worker 处理数据,避免阻塞主线程,从而保持页面的流畅性。
适用场景: 大量数据需要复杂计算或预处理。
如果需要前端计算(如排序、筛选),可以用 Web Worker 在后台线程执行,避免 UI 卡死。
异步计算,不影响主线程渲染。
代码
// worker.js self.onmessage = function (e) { const sortedData = e.data.sort((a, b) => a.value - b.value); self.postMessage(sortedData); };
const worker = new Worker("worker.js"); worker.postMessage(bigData); worker.onmessage = function (e) { setTableData(e.data); };
首屏加载速度慢怎么解决?
一、什么是首屏加载
指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容 首屏加载可以说是用户体验中最重要的环节
二、加载慢的原因
1.网络延时问题
cdn,用户节点就近
preload 预加载
prereder 预渲染
2. 资源太大
a.包分chunk
b.懒加载
c.公共资源 vender
d.缓存(不变动的使用强缓存;变动的使用协商缓存; 离线环境下使用策略缓存,service-worker)
e.服务端渲染(DOM树在服务端生成,然后返回给前端。)
f. 局部SSR,(广告页/营销活动页等)
3.资源是否重复发送请求去加载了
4.加载脚本的时候,渲染内容堵塞了
三、解决方案
减小入口文件积
常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,使得入口文件变小,加载速度大大增加; 在vue-router配置路由的时候,采用动态加载路由的形式: routes:[ path: 'Blogs', name: 'ShowBlogs', component: () => import('./components/ShowBlogs.vue') ] 以函数的形式加载路由,这样就可以把各自的路由文件分别打包,只有在解析给定的路由时,才会加载路由组件
静态资源本地缓存
采用HTTP缓存
采用Service Worker离线缓存
前端合理利用localStorage
UI框架按需加载
图片资源的压缩
图片资源虽然不在编码过程中,但它却是对页面性能影响最大的因素 对于所有的图片资源,我们可以进行适当的压缩 对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。
组件重复打包
假设A.js文件是一个常用的库,现在有多个路由使用了A.js文件,这就造成了重复下载 解决方案:在webpack的config文件中,修改CommonsChunkPlugin的配置 minChunks: 3 表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件
开启GZip压缩
使用SSR,也就是服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器
指标
First Contentful Paint (FCP) - 首次内容绘制时间
衡量从开始加载页面到页面上的第一个内容元素(如文本、图像、SVG 等)绘制到屏幕上的时间。这是用户感知到的第一个信号,表明页面开始加载内容。
Largest Contentful Paint (LCP) - 最大内容绘制时间:
衡量页面上最大的内容元素(通常是一个大的图片或视频背景)从开始加载到渲染完成的时间。LCP 是一个关键的用户体验指标,因为它反映了页面主要内容的加载速度。
First Meaningful Paint (FMP) - 首次有意义绘制时间
这一指标虽然不是官方标准的一部分,但它是评估页面何时变得有用的一个度量。它衡量的是页面首次呈现有意义的内容给用户的时间,即页面的主要内容已加载完毕并且视觉上稳定的时间。
Time to Interactive (TTI) - 交互就绪时间
衡量页面从开始加载到完全可用、响应用户输入所需的时间。在这段时间之后,页面应该可以快速响应用户的点击、触摸等交互。
Total Blocking Time (TBT) - 总阻塞时间
衡量从 FCP 到 TTI 之间,页面被认为是不可响应的时间总和。这个指标帮助识别那些使得页面无法立即响应用户输入的长时间任务。
Speed Index (SI) - 速度指数
速度指数是一种量化指标,它衡量页面内容在多快的时间内出现在可视区域。它记录了页面在一定时间内渲染了多少像素。
Cumulative Layout Shift (CLS) - 累积布局偏移
这是一个用户体验指标,用于测量页面在加载过程中发生的意外布局变化的程度。良好的 CLS 分数表示页面在加载期间保持了视觉稳定性。
First Byte Time (TTFB) - 第一个字节时间
衡量从浏览器发送请求到服务器返回第一个字节数据的时间。TTFB 反映了服务器端处理请求的速度以及网络延迟。
大屏适配几种方案
方案一:vw(单位)
假设设计稿尺寸为 1920*1080,直接使用 vw 单位,屏幕的宽默认为 100vw,那么100vw = 1920px, 1vw = 19.2px 。
新建px2vw.scss
/ 使用 scss 的 math 函数 @use "sass:math"; // 默认设计稿的宽度 $designWidth: 1920; // 默认设计稿的高度 $designHeight: 1080; // px 转为 vw 的函数 @function vw($px) { @return math.div($px, $designWidth) * 100vw; } // px 转为 vh 的函数 @function vh($px) { @return math.div($px, $designHeight) * 100vh; }
vue.config.js文件
module.exports = { ...,//其他设置 css: { loaderOptions: { sass: { prependData: `@import "@/styles/px2vw.scss";`, }, }, }, };
vite.config.ts配置
return { ...,//其他配置 css: { preprocessorOptions: { scss: { javascriptEnabled: true, additionalData: `@use "@/styles/px2vw.scss" as *;`, }, }, }, };
使用
<style lang="scss" scoped="scoped"> /* 直接使用 vw 和 vh 函数,将像素值传进去,得到的就是具体的 vw vh 单位 */ .box{ width: vw(300); height: vh(100); font-size:0pt; color:#303030;"> background-color: black; margin-left: vw(10); margin-top: vh(10); border: vh(2) solid red; } </style>
图表自适应
echarts 的字体大小只支持具体数值(像素),不能用百分比或者 vw 等尺寸,一般字体不会去做自适应,当宽高比跟 ui 稿比例出入太大时,会出现文字跟图表重叠的情况
封装一个工具函数,来处理图表中文字自适应了
chartsUtil.js
其原理是计算出当前屏幕宽度和默认设计宽度的比值,将原始的尺寸乘以该值
另外,其它 echarts 的配置项,比如间距、定位、边距也可以用该函数
// Echarts图表字体、间距自适应 export const fitChartSize = (size,defalteWidth = 1920) => { let clientWidth = window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth; if (!clientWidth) return size; let scale = (clientWidth / defalteWidth); return Number((size*scale).toFixed(3)); }
2.将工具函数挂载到vue
import {fitChartSize} from '@src/utils/chartsUtil.js' Vue.prototype.fitChartFont = fitChartSize;
3.组件中使用
getEchart() { let myChart = this.$echarts.init(this.$refs.chart); const option = { ...,//其他设置 grid: { left: this.fitChartSize(10), right: this.fitChartSize(20), top: this.fitChartSize(20), bottom: this.fitChartSize(10), containLabel: true, }, } myChart.setOption(option, true); },
方案二:scale(缩放)强烈推荐
通过监听浏览器窗口的大小,来改变scale的比例,从而实现数据大屏适配
实现步骤
1. 获取数据大屏展示内容区域的 DOM 元素。
2. style.transform:这是访问元素的 transform 样式属性。transform 是一个 CSS 属性,用于对元素进行变换,例如旋转、缩放、平移等。
3. scale(${getScale()}):这部分代码中,getScale() 函数返回一个缩放比例,这个比例会应用在 scale() 函数中。这样,页面元素会按照指定的比例进行缩放。缩放比例是根据窗口大小和设计稿大小计算的,以确保内容适应不同的屏幕尺寸。
4. translate(-50%, -50%):这部分代码中,translate() 函数用于对元素进行平移。在这里,它将元素的中心点平移到屏幕的中心。
5. transform-origin 是 CSS 属性,用于指定元素的变换(比如旋转、缩放、平移等)的原点位置,即元素围绕哪个点进行变换操作。在你提供的样式中,transform-origin 设置为 left top,这意味着元素的变换原点位于元素的左上角
缺点
因为是根据 ui 稿等比缩放,当大屏跟 ui 稿的比例不一样时,会出现周边留白情况
当缩放比例过大时候,字体会有一点点模糊,就一点点
当缩放比例过大时候,事件热区会偏移
方案三:插件v-scale-screen
它其实也是通过 scale 进行等比例计算放大和缩小的,和方案二的原理是一样的,还可以通过api调整样式,源码地址和对应的API
vue2方案
1.使用v-scale-screen@1.0.0版本
npm install v-scale-screen@1.0.0 -save # or yarn add v-scale-screen
2.main中引入并使用
// main.js import VScaleScreen from 'v-scale-screen' Vue.use(VScaleScreen)
3.组件中使用
<template> <v-scale-screen width="1920" height="1080" :boxStyle="boxStyle"> <div> ... </div> </v-scale-screen> <template> <script> export default { data() { return { boxStyle: { backgroundColor: 'green' }, } } </script>
vue3方案
1.使用v-scale-screen@2.0.0版本
npm install v-scale-screen@2.0.0 -save
2.组件中使用
<template> <v-scale-screen width="1920" height="1080"> <div> ... </div> </v-scale-screen> </template> <script setup> import VScaleScreen from 'v-scale-screen' </script>
postcss-px-to-viewport postcss-pxtorem 缺点
只转换style内的样式,不转换行内样式
echarts 内部配置的样式不能转
src/main.js
function px2rem(px){ if(/%/ig.test(px)){ // 有百分号%,特殊处理,表述pc是一个有百分号的数,比如:90% return px }else{ return (parseFloat(px) / 37.5) + 'rem' } } Vue.prototype.$px2rem = px2rem // 放到全局
使用
H5 如何解决移动端适配问题
移动端适配问题是指如何让⽹面在不同的移动设备上显⽰效果相同。
⽅案
1.使⽤ viewport 标签
通过设置 viewport 标签的 meta 属性,来控制⻚⾯的缩放⽐例和宽度,以适配不同的设备 <meta name="viewport" content="width=device-width, initial-scale=1.0">
2.使⽤ CSS3 的媒体查询@media
3.直接使⽤ rem 单位
html {font-size:0pt; color:#303030;} @media screen and (max-width: 640px) { html {font-size:0pt; color:#303030;">} div {width: 10rem;}
间接使用rem
4. 使⽤ flexible 布局⽅案
<script src="https://cdn.bootcdn.net/ajax/libs/lib-flexible/0.3.4/flexible.js"</script> import 'lib-flexible/flexible.js'
flexible.js 会在⻚⾯加载时动态计算根节点的字体⼤⼩,并将 px 转化为 rem 单位。在样式中可以直接使⽤ px 单位
5. post-css-pxtorem将PX转为rem:根据屏幕宽度动态设置html的font-size
function resizeRootFontSize() { const designWidth = 750; // 设计稿宽度,例如iPhone 6/7/8的设计稿宽度 const maxWidth = 1080; // 最大适配宽度 const minFontSize = 10; // 最小字体大小 const maxFontSize = 20; // 最大字体大小 const screenWidth = Math.min(window.innerWidth, maxWidth); const fontSize = Math.max(minFontSize, (screenWidth / designWidth) * 16); document.documentElement.style.fontSize = `${fontSize}px`; } window.addEventListener('resize', resizeRootFontSize); window.addEventListener('orientationchange', resizeRootFontSize); resizeRootFontSize();
你是怎么做项目技术选型的?
1:项目因素
首先要考虑项目的需求和目标。不同类型的项目可能需要不同的技术栈。如果要做一些简单的静态网页项目,比如各种独立的活动页,宣传页啥的,什么顺手用什么,没必要太纠结技术选型。如果网站比较注重SEO,那可以选择考虑nuxt.js和next.js。如果是需要跨端,可以选择flutter、react native、uniapp、Taro等。对于正式、周期长、稳扎稳打类的项目,肯定要选择一个现代的前端框架。
2:技术因素
了解候选技术的特点和特性,比较它们在易用性、开发体验、性能、生态系统和社区支持等方面的优势和劣势。比如易用性,Angular 和 Vue,Angular 学习曲线陡峭,需要比较长的学习时间。而Vue比较简单,看文档一两天就能上手干活。
团队因素。需要考虑团队成员的技术栈、后期招聘成本、新人的学习成本。选择团队成员熟悉的技术栈更容易提高开发效率和降低学习成本,而且选用的技术栈会直接影响到团队后续招聘成本,比如大部分前端的技术栈都是vue和react,如果你偏偏技术选型用Angular。那肯定会增加招聘难度了。新人的学习成本也很重要,如果选择的技术需要新人花费一段时间去学习,去适应,那肯定无形之中就耽误了大量的时间。
生态系统和社区支持因素:评估候选技术的生态系统和社区支持情况。社区是否活跃、配套设施是否全面、是否经常维护、官方文档是否全面等等,一个活跃和健康的社区可以提供更多的资源、工具和支持,有助于快速解决问题和获取最新的技术发展。
性能因素:需要针对不同场景带来的不同性能表现,来决定技术的使用场景。比如你们要做游戏开发,那就可以直接考虑游戏引擎,如Cocos,Unity等
可扩展性和可维护性:需要考虑该技术在项目规模扩大时的可扩展性和可维护性。考虑技术的模块化支持、组件化开发、代码结构和测试等方面,以确保项目能够长期维护和扩展。
前端如何防止接口重复提交?
按钮禁用
加载loading
接口锁定
我们可以在axios请求中进行统一封装,使用一个变量来记录当前正在处理的请求,在发送请求前,先检查是否正存在相同的请求,如果存在则不发送新的请求,如果不存在,再继续发送请求。
唯一标识符。
前端每次请求前,都生成一个唯一标识符,比如UUID这种,并将该标识符作为请求的一部分发送到后端。后端接收到请求后,检查该标识符是否已经处理过,如果已经处理过则不再处理。
防抖或节流
前端如何实现token的无感刷新?
一般是为了解决频繁登录造成的用户体验问题,所以需要前端定时去刷新token,以帮助用户静默登录。
第一种,由后端同学来返回过期时间,前端在每次请求的时候,判断token的过期时间,如果快到过期时间,就去调用刷新token接口。 不过,这种方案不仅需要后端额外提供一个token过期时间,而且当前端用本地时间判断,本地时间又被修改的情况下,就会造成判断不准确,所以不推荐。
第二种,前端写个setInterval定时器,定时去检查距离用户登录时间是否超过某个时间段,然后去刷新token接口, 这种方案比较浪费资源,所以不建议使用。
第三种,可以在axios请求响应拦截器中拦截,当判断token过期后,调用刷新token的接口,这种方案不需要后端额外返回字段,也不会浪费资源,是比较推荐的。 需要注意几点: 第一点就是需要防止多次刷新token。我们可以在请求刷新token接口前,新增一个字段用来判断此时是否刷新token中,如果不是,那就走刷新token逻辑,如果是,那就绕过刷新token逻辑。 第二点,如何处理并发请求的场景,比如,用户使用promise.all同时发起多个请求,导致这几个请求都进入到判断token刷新的逻辑中了,该怎么解决?我们可以先把这些请求都存储到一个promise数组中,等token刷新结束后,再统一执行这个数据,把存储的接口都统一再请求一次。