这篇文章给大家分享的是有关前端性能优化的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
反复看下以下三个问题。
有木有不同的人问过你:什么是前端性能优化?
有木有不同的面试官问过你:你为前端性能优化做过什么?
有木有哪一次,你问过自己:别人问我前端性能优化到底应该如何答复?
你有木有一套自己的关于性能优化的答案,能让技术大牛和你一起探讨,也能让小白点头称是。
假如你有,那你的答案在哪。
例如整个天猫首页。答案有很多种,你看看有木有你想的那种。
create-react-app
初始化一个项目吧。 首页写好一些组件,例如豆腐块、Header、Bar
、长滚动ScrollView
。然后项目编译、打包上线。
webpack
手搭一个项目。
路由按需加载弄上,可无痕浏览的带loadmore
的高性能ScrollList
。
因为是首页,明显会牵扯到首屏幕加载的问题。那骨架屏给安排上吧。
再搞一套webpack的最佳实践,目的是能最终得到体积尽量小的打包文件。
SSR来一套吧。因为首页DOM结构太复杂了,如果走Virtual DOM
那一套,等到GPU渲染UI就太慢了。
以上,有命中你的某个点吗? 不管有木有道理,这是你想到的点吗?是不是总感觉好像少了点什么?
本篇文章不细讲其它内容。 但到这了就得提一嘴,留个印象。
系统层设计
一个新系统留20%来满足当前已有业务。 剩下80% 用来系统演进。可以思考下,天猫首页一直变,却依然能保证性能达标。
业务层设计
已有业务是否与其它业务产生了耦合,是否存在前置业务,如果有那前置业务的权限又在哪里。已有业务是否能根据系统演进程度不断兼容新业务?
应用层设计
例如微前端,例如组件库,例如
npm install
webpack优化
骨架屏
路有动态按需加载
代码层设计
写好高性能React 代码?如何利用好Vue3 时间切片?
不说了。太初级的浪费慢慢积累就好。
所以,你应该发现了“总感觉好像少了点什么” 是少在哪里了。对,前端性能优化不仅仅是应用层面、代码层的优化,更重要的是系统层、业务层的优化。
看了以上的心理预设,那接下来就进入正式进入主题吧。
尝试着走完下面这个流程:
性能指标设定(FPS、页面秒开率、报错率、请求数等)
如何让老板了解你的优化方案?假如你的老板不懂技术。
告诉老板,页面白屏时间减少了0.4s。
告诉老板,弱网情况下首页秒开。
告诉老板,以前http请求量大导致服务器压力太大了,现在每个页面最多只有不到5个请求是向服务器要资源的。
告诉老板……
性能标准确定
确认要哪些指标
收益评估
面向老板满意编程。 /捂脸.png (手动狗头)
诊断清单
清单上会告诉你各项指标的数据。
优化手段
WebView 性能优化
并行初始化
资源预加载
数据接口请求优化
前端架构性能调优
长列表性能优化
打包优化
组件骨架屏
图片骨架屏
懒加载
缓存
离线化
并行化
保证首次加载为秒开的离线包设计
App 启动阶段的优化方案
页面白屏阶段的优化方案
首屏渲染阶段的优化方案
Hybrid APP 性能优化
首评秒开的X种方法?
骨架屏
NSR
SSR
webView
层及代码架构层面优化
性能立项
确定了就去搞起来吧。
性能实践
做好准备,尽情的在各种恶劣环境下把页面快速的折腾出来吧!
现在,你对前端性能优化有了一个完整的认知了吗?很多时候谈论到性能优化首先需要谈到如何对性能进行“确诊”。虽然大部分情况,你不会被人问到是如何对性能进行监控的。(说话声音越来越小。。。)
接下来就细谈优化手段
最常见的优化手段之一。
懒加载是指在长页面加载过程时,先加载关键内容,延迟加载非关键内容。比如当我们打开一个页面,它的内容超过了浏览器的可视区口大小,我们可以先加载前端的可视区域内容,剩下的内容等它进入可视区域后再按需加载。
举个栗子。天猫首页精选。上图。
正好是天猫618活动。这个IOS版的天猫首页精选。如果你经常访问天猫首页精选,你会发现它已经几乎做到了无痕浏览。懒加载在这就被运用的很好,当然,这里不仅仅是做了懒加载才达到这样的效果。
那只说懒加载,天猫首页精选做了什么呢? 猜猜看。
懒加载
图片懒加载
图片是native
做过缓存的。
在可视区域出现才会加载
卡片预先加载(懒加载的时机改变)
并不是进入可视区域才加载卡片的。而是当上一张卡片进入可视区域就预先加载下一张卡片。 因为相对于图片,加载卡片UI会快得多。 这也是无痕浏览的保障之一。
动画懒加载
假如你快速的进行划屏滚动,List
滚动高度发生很大变化,那请求数据最终还是会敌不过你的高速滑动。也就是说,在没有新的数据之前你看不到下一张卡片了,这是你必须等待了。这时候就会有一个loading
的动画显示,接着等拿到了新数据,新卡片就会出现并且自动完全滑入可视区域。
这里会有人说了,IOS
的阻尼本来就会使得动画、滚动效果更加顺畅。在这里为想说的是,Android
也一样可以。
如果说懒加载本质是提供首屏后请求非关键内容的能力,那么缓存则是赋予二次访问不需要重复请求的能力。在首屏优化方案中,接口缓存和静态资源缓存起到中流砥柱的作用。
回到刚才懒加载提到的那个问题,为什么你要快速划屏一段时间才会遇见没有新数据的情况?原因就是缓存的数据已经用完了,所以只能让服务器给予最新的数据。
接口缓存接口缓存的实现,如果是端内的话,所有请求都走 Native 请求,以此来实现接口缓存。为什么要这么做呢?
App 中的页面展现有两种形式,使用 Native 开发的页面展现和使用 H5 开发的页面展现。如果统一使用 Native 做请求的话,已经请求过的数据接口,就不用请求了。而如果使用 H5 请求数据,必须等 WebView 初始化之后才能请求(也就是串行请求),而 Native 请求时,可以在 WebView 初始化之前就开始请求数据(也就是并行请求),这样能有效节省时间。
那么,如何通过 Native 进行接口缓存呢?我们可以借助 SDK 封装来实现,即修改原来的数据接口请求方法,实现类似 Axios 的请求方法。具体来说就是,把包括 post、Get 和 Request 功能的接口,封装进 SDK 中。
这样,客户端发起请求时,程序会调用 SDK.axios 方法,WebView 会拦截这个请求,去查看 App 本地是否有数据缓存,如果有的话,就走接口缓存,如果没有的话,先向服务端请求数据接口,获取接口数据后存放到 App 缓存中。
静态资源缓存先看图。
91 requests,113 kB transferred, 2.2 MB resources,Finish: 2.93 s,DOMContentLoaded: 177 ms.
2.2M的资源,达到秒开。看看Size那一列,你就应该好像领悟到什么了。
没错。HTTP缓存。 数据接口的请求一般来说较少,只有几个,而静态资源(如 JS、CSS、图片和字体等)的请求就太多了。以天猫首页为例,91 个请求中除了少数script外,其余都是静态资源请求。
那么,如何做静态缓存方案呢?这里有两种情况,一种是静态资源长期不需要修改,还有一种是静态资源修改频繁的。你可以尝试多刷新几次页面看看。
资源长期不变的话,比如 1 年都不怎么变化,我们可以使用强缓存,如 Cache-Control 来实现。具体来说可以通过设置 Cache-Control:max-age=31536000,来让浏览器在一年内直接使用本地缓存文件,而不是向服务端发出请求。
至于第二种,如果资源本身随时会发生改动的,可以通过设置 Etag 实现协商缓存。具体来说,在初次请求资源时,设置 Etag(比如使用资源的 md5 作为 Etag),并且返回 200 的状态码,之后请求时带上 If-none-match 字段,来询问服务器当前版本是否可用。如果服务端数据没有变化,会返回一个 304 的状态码给客户端,告诉客户端不需要请求数据,直接使用之前缓存的数据即可。当然,这里还涉及 WebView相关的东西,先不细讲。。。
离线化是指线上实时变动的资源数据静态化到本地,访问时走的是本地文件的方案。
离线包
就是一是离线化的一种方案,是将静态资源存储到 App 本地的方案,这里先不细讲。
但更复杂的另一种离线化方案:把页面内容静态化到本地。离线化一般适合首页或者列表页等不需要登录页面的场景,同时能够支持 SEO 功能。
那么,如何实现离线化呢?在打包构建时预渲染页面,前端请求落到 index.html 上时,已经是渲染过的内容。此时,可以通过 Webpack 的 prerender-spa-plugin 来实现预渲染,进而实现离线化。
Webpack 实现预渲染的代码示例如下:
// webpack.conf.js var path = require('path') var PrerenderSpaPlugin = require('prerender-spa-plugin') module.exports = { // ... plugins: [ new PrerenderSpaPlugin( // 编译后的html需要存放的路径 path.join(__dirname, '../dist'), // 列出哪些路由需要预渲染 [ '/', '/about', '/contact' ] ) ] } // 面试的时候离线化能讲到这,往往就是做死现场,但风险和收益成正比,值得冒险。那就是,你有木有自己的预渲染方案。
如果说懒加载、缓存和离线化都是在请求本身搞事情,想尽办法减少请求或者推迟请求,那并行化则是在请求通道上优化问题,解决请求阻塞问题,进而减少首屏时间。
例如广州打疫苗排队,新闻上报道是如何如何阻塞。 那除了让群众错开打疫苗的时间,还可以增加打疫苗的医生数量。我们在处理请求阻塞时,也可以加大请求通道数量——借助于HTTP 2.0
的多路复用方案来解决。
HTTP 1.1
时代,有两个性能瓶颈点,串行的文件传输和同域名的连接数限制(6个
)。到了HTTP 2.0
时代,因为提供了多路复用的功能,传输数据不再使用文本传输(文本传输必须按顺序传输,否则接收端不知道字符的顺序),而是采用二进制数据帧和流的方式进行传输。
其中,帧是数据接收的最小单位,流是连接中的一个虚拟通道,它可以承载双向信息。每个流都会有一个唯一的整数 ID 对数据顺序进行标识,这样接收端收到数据后,可以按照顺序对数据进行合并,不会出现顺序出错的情况。所以,在使用流的情况下,不论多少个资源请求,只要建立一个连接即可。
文件传输环节问题解决后,同域名连接数限制问题怎么解决呢?以 Nginx 服务器为例,原先因为每个域名有6
个连接数限制,最大并发就是 100
个请求,采用 HTTP 2.0
之后,现在则可以做到 600
,提升了 6
倍。
你一定会问,这不是运维侧要做的事情吗,我们前端开发需要做什么?我们要改变静态文件合并(JS、CSS、图片文件)和静态资源服务器做域名散列这两种开发方式。
具体来说,使用 HTTP 2.0
多路复用之后,单个文件可以单独上线,不需要再做 JS 文件合并了。这里提一个保留问题,用过阿里系的Antd组件库吧?库每次更新都不是全部更新,可能这次只更新一个Button
组件,再次只更新一个Card
组件。那是如何做到单独组件单独发版的呢?
为了解决静态域名阻塞(这是个性能瓶颈点),需要将静态域名分为 pic0-pic5,这样能提升请求并行能力。
虽然通过静态资源域名散列的办法解决了问题,但DNS 解析时间会变长很多,同时还需要额外的服务器来满足。HTTP 2.0
多路复用解决了这个问题。
感谢各位的阅读!关于“前端性能优化的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。