当前位置: 首页 > 科技观察

深度解读Web前端性能优化,这些细节不容忽视

时间:2023-03-17 20:04:17 科技观察

导读:用户体验是Web产品非常重要的一环。影响用户留存。体验差的网站各有千秋,但体验好的网站往往有一些共性。这些优秀的特性凝聚了设计师、研发工程师和产品经理的大量智慧。访问交互速度快,动画效果流畅流畅,用户操作反馈简单。整个站点的操作步骤是一致的。主要内容位于最显眼的位置。不同人群可以使用它。在这些优秀体验的特点中,最容易引起人们共鸣的往往是网站的性能,比如网站访问和交互的速度。如何发现性能问题?如何优化性能(性能优化的常规方法和框架方法)?如何衡量效益?基于多年的性能优化实践,本文着重分享一些首屏性能优化的经验。01表演收藏家欲磨刀刃,必先利其器。我们说的性能采集不是性能分析Devtools,而是指在产品真实用户访问的大数据中进行采样,为采样用户采集性能数据,获取产品在真实用户环境下的性能数据。所有浏览器制造商都已经意识到性能对于Web开发的重要性。为了解决目前性能测试难的问题,W3C推出了一套性能API标准,目的是简化开发者对网站性能进行精确分析和控制的过程。开发人员采取措施提高网络性能。整套标准包括10多种API,它们目前在规范过程中的进展情况如下图所示。图:PerformanceAPIStandard(节选图片)这套标准提供了NavigationTiming、ResourceTiming、UserTimingUserTiming和PerformanceTimeline规范,帮助开发者准确衡量文档导航时间、页面上资源的访问以及开发者脚本的执行。在这套API中,页面加载NavigationTiming和页面资源加载ResourceTiming这两个API可以帮助我们获取页面的Domready时间,onload时间,白屏时间,以及单个页面资源从发送请求的阶段获得响应,例如带宽、延迟或主页的整体页面加载时间等性能参数,所有这些都基于真实用户数据(RUM)。图:NavigationTiming关系图(摘自W3C)在获取用户访问时序数据的前提下,我们可以结合具体的业务场景定义访问性能的核心指标,比如白屏时间、首屏时间FSP、用户交互时间TTI、页面加载时间作为核心优化指标,其中首屏时间和用户交互时间需要单独定制。还可以通过获取DNS查询耗时、TCP连接耗时、request请求耗时、dom树解析耗时、白屏时间、domready时间、onload时间等进行性能分析,然后对这些细节进行性能优化根据症状分期。这些参数由上面的performance.timing属性之间的差异组成。通过使用API??采集各个阶段的性能指标,等待获取到所有数据,然后通过网络请求将数据发送到服务器进行后续的数据分析。02性能优化快速加载、及时响应用户反馈、流畅的动画、类似原生APP的沉浸式用户体验是Web应用性能优化的目标,主要涉及两个方面:加载性能和渲染性能。本章介绍了一些通用的优化方法和框架级的优化方案。2.1加载性能优化网页通常由HTML、CSS、JavaScript等多媒体资源组成,充斥着各种同步和异步资源。这些资源必须在页面加载时从服务器获取。2.1.1减少资源大小,压缩文本内容,优化JavaScript第三方库,引入压缩,虽然简单,但是非常有效,也是最广泛的资源大小优化操作。很多工具可以帮助我们压缩HTML、CSS、JavaScript、图片等,比如TerserPlugin可以用来压缩JavaScript,PostCSS可以用来压缩CSS和完成前缀自动补全。除了压缩单个文件外,在服务器上配置Gzip也很重要。Gzip对文本资源的压缩效果非常明显,体积通常可以重新压缩到原来大小的30%左右。但是,Gzip不适用于非文本资源,例如已单独压缩的图像。如果我们只需要使用工具库中的几个简单功能,可以考虑使用原生JavaScript。不计后果地引入第三方库会迅速增加JavaScript资源的大小。2.1.2资源缓存缓存在优化页面加载性能方面起着重要作用。缓存无处不在,包括浏览器、网络代理和服务器缓存,它们往往可以大大加快响应速度。图:Web全链接缓存HTTP缓存LocalStorageCacheStorageIndexedDBCDN现代浏览器都实现了HTTP缓存机制。浏览器第一次获取资源后,会根据HTTP响应头中的Cache-Control和ETag字段,为资源确定强缓存策略或协商缓存策略。LocalStorage主要作为本地存储,解决了cookie存储空间不足的问题(cookie中每个cookie的存储空间为4k),一般浏览器在localStorage中支持5M大小。CacheStorage用于存储Response对象,也就是说用于缓存HTTP响应,通常用在PWA技术中。IndexedDB是一种在浏览器中持久存储数据的方法,使我们能够创建具有丰富查询功能的离线Web应用程序,而无需考虑网络可用性。内容缓存在位于用户访问点的CDN网络节点中。它是面向最终用户的内容提供设备。可以缓存静态网页内容和流媒体内容,实现内容的边缘传播和存储,让用户就近访问。2.1.3调整资源优先级通过调整资源加载优先级,保证主要内容能够快速加载,通过预加载、延迟加载等方式调整资源加载行为,优化网页加载性能。Pre-loading预连接和DNS预解析PrefetchinglazyloadingServiceWorker提前声明了当前页面需要的资源,以便浏览器预加载这些资源。通过media属性进行媒体查询,根据响应情况有选择地预加载资源。预连接会提前完成DNS解析、TCP握手和TLS协商,但不会提前加载资源。也可以考虑使用它提前与资源建立socket连接。浏览器会在空闲时下载优先级最低的预取资源。预取通常用于通过声明在点击“下一页”的页面动作之前预加载用户接下来可能需要的html资源。按需加载和延迟加载都属于懒加载的范畴。比如图片资源采用了“懒加载”策略,即只加载当前在视口中的图片。对于未在视口外加载的图像,它们即将滚动到视口中开始加载。使用ServiceWorker线程与主线程分离,用于持久离线缓存Web资源和请求。2.1.4合理拆分代码浏览器支持资源的并行加载,合理拆分资源也是一种有效的优化方法。为了获得更好的结果,我们通常不需要在第一个屏幕上一次加载所有的JavaScript代码。合理拆分代码,区分开发环境和生产环境使用少量主代码,拆分出当前不需要的代码,可以有效加速首页。屏幕显示的速度。使用webpack区分开发环境和生产环境来配置和打包资源,可以有效优化代码。Treeshaking可以通过静态分析(仅ES模块支持)更好地优化和修剪模块间的依赖关系。webpack-bundle-analyzer是一款webpack构建产品的可视化插件,可以清晰的看到构建产品的体积,帮助分析后续的优化方向。2.1.5HTTP/2HTTP/2给WEB带来了很大的性能提升。同时,多路复用、头部压缩、ServerPush等特性使得在一个连接上同时开启多个流,实现数据双向传输成为可能。服务器可以在发送页面HTML时主动推送其他资源,而不是等待浏览器解析到相应位置,发起请求然后响应。图:http1vshttp22.2渲染性能优化浏览器在渲染页面之前,首先将HTML文本内容解析为DOM,将CSS解析为CSSOM。DOM和CSSOM都是树状数据结构,相互独立,但有相似之处。然后浏览器将DOM和CSSOM树合并到渲染树中。从DOM树的根节点开始遍历,找到CSSOM树中节点对应的样式规则,合并到渲染树中的节点中。在遍历过程中,不可见的节点将被忽略。渲染树然后用于布局,即计算渲染树节点在浏览器视口中的确切位置和大小。浏览器布局的性能开销很高,我们需要注意不要频繁触发页面重新布局。浏览器在获取渲染树节点的几何布局信息后,可以将节点绘制到屏幕上,包括绘制文字、颜色、边框和阴影。绘图过程首先根据布局和视觉相关的样式信息生成一系列绘图操作,然后进行光栅化(光栅化是将矢量图形格式表示的图像转换成位图用于显示或打印机输出的过程),转换将要绘制的item制作成位图存入GPU,最后通过图形库在屏幕上绘制像素点。图:浏览器渲染过程页面不是一下子画完。实际上,页面被分成多个层进行绘制,这些层会在一个单独的线程中被绘制到屏幕上。这个过程称为合成。合成线程可以对图层进行剪切和变换,因此可以用来响应用户的滚动、缩放等基本操作,而不受主线程阻塞的影响。2.2.1关键渲染路径由于渲染是在主进程中进行的,因此合理利用主进程进行渲染非常重要。首屏渲染所需要的关键资源共同构成了关键渲染路径。减少非关键渲染路径的资源消耗,可以有效提升渲染速度。延迟非关键CSS加载async和deferWeb应用程序通常会有一些CSS不会用于首屏渲染,例如弹出框的样式。任何通过引用传递的CSS都会在加载时阻止页面呈现。为了不让这些非关键的CSS阻塞页面渲染,可以拆分资源,延迟非关键资源的加载。由于渲染是在主进程中进行的,因此合理利用主进程进行渲染非常重要。首屏渲染所需要的关键资源共同构成了关键渲染路径。减少非关键渲染路径的资源消耗,可以有效提升渲染速度。2.2.2非阻塞JavaScript用户对不流畅的滚动或动画非常敏感,一般要求页面帧率达到每秒60帧。由于JavaScript一般是单线程执行的,长时间运行的任务会阻塞浏览器主线程,导致页面无响应,造成卡顿和假死。页面滚动requestAnimationFrame任务在浏览器渲染下一帧前执行requestIdleCallback安排任务在浏览器空闲时执行WebWorkers当我们监听touchstart,touchmove等事件时,合成线程不知道我们是否会通过event.preventDefault()防止默认的滚动行为,这样每次触发事件时,它都会等待事件处理程序完成,然后再滚动页面。这通常会导致明显的延迟,从而影响页面滚动的流畅性。通过在addEventListener()时声明{passive:true},表示事件处理器不会阻止页面滚动,从而可以更快的响应用户的操作。我们可以把一些比较耗性能的逻辑放在工作线程中处理,让主线程继续响应用户操作,渲染页面。2.2.3降低渲染树的计算复杂度。结构越复杂的页面性能往往越差,动画越多的页面越容易卡住。降低查找和匹配元素的成本减少布局的数量优化绘制和合成渲染树是由DOM和CSSOM树合并形成的。对于每一个DOM元素,都需要找到与该元素相匹配的样式规则。CSSModules是比较主流的CSS-in-JS方案。使用webpack等构建工具,可以为类选择器生成一个自定义格式的唯一类名,也可以减少浏览器匹配CSS选择器的开销。浏览器执行一次布局的代价是非常大的,所以我们要尽量避免直接修改这些属性,尤其是布局属性不要用于动画效果,否则会出现明显的掉帧。修改大部分样式属性都会导致页面重绘,这是很难避免的。唯一的例外是变换和不透明,因为它们只能由合成器操作层实现。Transform和opacity很适合做动画效果,但是我们还是需要通过will-change为它们创建独立的layer,避免影响其他layer的绘制。2.3框架优化方法CSR、SSR、NSR、ESR、混合离线包、Bigpipe、appcache等都是不错的方法。2.3.1CSR(ClientSideRender)浏览器渲染,顾名思义,就是所有的页面渲染、逻辑处理、页面路由、接口请求都发生在浏览器中,即向服务器请求一个简单的HTML文件,并执行在HTML上添加内容中的JavaScript。事实上,现代主流的前端框架都采用这种渲染方式。这种渲染方式的好处是实现了前后端架构分离,方便前后端职责分离,可以快速有效的减少首次渲染的白屏时间。同时,CSR可以通过在打包编译阶段进行预渲染或骨架屏生成,进一步提升首渲染的用户体验。图:CSR2.3.2SSR(ServerSideRender)服务器端渲染是在服务器端完成页面的渲染,在服务器端完成页面模板、数据填充、页面渲染,然后返回完整的HTML内容到浏览器。由于所有渲染工作都在服务器端完成,因此网站的首屏时间和TTI会表现得更好。图:SSR但是渲染需要在服务端完成,前后端职责分离不好,白屏时间会比较长。同时对服务器端的负载要求也会比较高。2.3.3NSR(NativeSideRender)GMTC2019全球大前端技术UC团队提到了一个0.3秒“出道”的方案。该方案适用于混合开发。NSR本质上是分布式SSR。通过加载离线页面模板,Ajax预加载页面数据,Native渲染生成Html数据缓存在客户端,将服务端的渲染工作放在独立的移动设备中,实现页面预加载,不增加额外的服务端压力。核心思想是通过浏览器开启一个JS-Runtime,预先渲染下载的html模板和预取的feed流数据,然后将html设置到内存级别的MemoryCache中,从而达到点击和点击的效果查看。图:NSR2.3.4ESR(EdgeSideRender)边缘渲染的核心思想是借助边缘计算能力,将静态内容和动态内容依次以流的方式返回给用户。与服务器相比,CDN节点距离用户更近,网络延迟更短。可缓存的页面静态部分在CDN节点上快速返回给用户,同时在CDN节点上发起动态部分内容请求,动态内容在响应流后返回给用户静态部分。图:ESR03收益测算速度是应用性能最直接的体现。绩效效益衡量也需要多维度、全面的分析比较。通过对等实验组和对照组核心指标中大量真实数据的分位数值对比,可以获得性能收益,数据收益也可以与用户PV、UV、收入相关联.监控网站真实用户可感知的白屏、首屏、交互等用户体验指标,也可以从服务端响应时间、网络延迟、DOM解析等细节指标的变化来进行日常性能优化.核心指标不同分位数占比数据统计。基于多平台浏览器性能分析,统计不同版本浏览器和设备类型的核心指标数据。不同地区(包括国家、省、市)、不同运营商和接入方式(包括2G/3G/4G/WiFi)的关键网络性能指标统计。图:性能平台业界最好的性能监控平台有ONEAPM、听云、性能魔方,各大公司和云平台也提供了很好的相关监控服务。04小结做事靠的不仅仅是历史经验教训的积累,还有一套系统的流程或模板。做性能优化是一件需要闭环思考的事情。尤其是这种端到端的优化,需要关注事前规划、事中执行、事后总结三个阶段,还需要结合不同的业务场景进行优化。与客户的合作不是机械的事情。就连很多大厂的前端业务也要在优化的同时解决历史包袱,慎重前行!随着优化业务的不断迭代和发展,如何巩固性能优化成果任重而道远,需要持续投入。掌握性能优化的基本原理,结合优秀的性能结构设计,或许是一种聪明的做法。参考Web性能优化资源合集(持续更新中)|微聊Web前端性能优化-https://naluduo.vip/Web-Performance-Optimization/reference/#%E8%B0%83%E8%AF%95%E5%B7%A5%E5%85%B7以用户为中心的性能指标-https://web.dev/i18n/zh/user-centric-performance-metrics/使用window.performance分析web前端性能-五艺-博客园-https://www.cnblogs.com/y896926473/articles/7466951.htmlHOME·PWA应用实战-https://lavas-project.github.io/pwa-book/网页渲染过程详解-https://www.jianshu.com/p/7659d714a642web缓存详解-https://zhuanlan.zhihu.com/p/90507417