首屏介绍
指用户打开网站开始,到浏览器首屏内容渲染完成的时间。对于用户体验来说,首屏时间是用户对一个网站的重要体验因素。通常一个网站,如果首屏时间在5秒以内是比较优秀的,10秒以内是可以接受的,10秒以上就不可容忍了。超过10秒的首屏时间用户会选择刷新页面或立刻离开。
首屏时间计算
首屏模块标签标记法
统计首屏内加载最慢的图片的时间
自定义首屏内容计算法
首屏模块标签标记法
通常适用于首屏内容不需要通过拉取数据才能生存以及页面不考虑图片等资源加载的情况,我们会在 HTML 文档中对应首屏内容的标签结束位置,使用内联的 JavaScript 代码记录当前时间戳。如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首屏</title>
<script type="text/javascript">
window.pageStartTime = Date.now();
</script>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="page.css">
</head>
<body>
<!-- 首屏可见模块1 -->
<div class="module-1"></div>
<!-- 首屏可见模块2 -->
<div class="module-2"></div>
<script type="text/javascript">
window.firstScreen = Date.now();
</script>
<!-- 首屏不可见模块3 -->
<div class="module-3"></div>
<!-- 首屏不可见模块4 -->
<div class="module-4"></div>
</body>
</html>
此时首屏时间等于 firstScreen - performance.timing.navigationStart
事实上首屏模块标签标记法 在业务中的情况比较少,大多数页面都需要通过接口拉取数据才能完整展示
统计首屏内加载最慢的图片的时间
通常我们首屏内容加载最慢的就是图片资源,因此我们会把首屏内加载最慢的图片的时间当做首屏的时间。
DOM树构建完成后将会去遍历首屏内的所有图片标签,并且监听所有图片标签 onload 事件,最终遍历图片标签的加载时间的最大值,并用这个最大值减去 navigationStart 即可获得近似的首屏时间。
此时首屏时间等于 加载最慢的图片的时间点 - performance.timing.navigationStart
自定义首屏内容计算法
由于统计首屏内图片完成加载的时间比较复杂。因此我们在业务中通常会通过自定义模块内容,来简化计算首屏时间。如下面的做法:
忽略图片等资源加载情况,只考虑页面主要 DOM
只考虑首屏的主要模块,而不是严格意义首屏线以上的所有内容
首屏优化方案
项目背景
项目较为复杂,模块较多,(当然不比大型电商网站),首页的请求就有8个,并且是精简之后的,稍有不慎,白屏现象就会很严重。体验极差。 首页模块划分
- 分类 2. 轮播图 3. 推荐 4. 收藏数 5. 购买数 6. 案例展示 7. 主内容展示 8. 合作机构展示
其中位于首屏的是1、2、3、4、5,对于6在大屏幕上也会展示。
请求优化
利用prerender-spa-plugin + Skeleton Screen (骨架屏) 对SPA进行预渲染
前端的资源动态加载:
a. 路由动态加载,最常用的做法,以页面为单位,进行动态加载。
b. 组件动态加载(offScreen Component),对于不在当前视窗的组件,先不加载。
c. 图片懒加载(offScreen Image),同上。值得庆幸的是,越来越多的浏览器支持原生的懒
加载,通过给img标签加上loading="lazy"来开启懒加载模式(vue-lazyload)。
Promise异步调用,控制首屏请求数量
浏览器缓存(localStorage)
静态文件缓存方案:这个最常看到。现在流行的方式是文件hash+强缓存的一个方案。比如hash+ cache control: max-age=1年。
pwa主要是用了它的离线缓存
引入http2.0:http2.0对比http1.1,最主要的提升是传输性能,特别是在接口小而多的时候。
开启gzip优化
全局WebView(移动spa)
部分前端请求改为服务端内网请求.
打包优化
添加externals,减少vendor.js体积,通过CDN的方式引入
tree-shaking:去除没用过的代码
UglifyJsPlugin:压缩代码
ExtractTextPlugin:提取css出来
开启gzip压缩,生成压缩文件
静态图片都传到阿里云上了,然后建了一个常量文件,进行管理
icon处理
渲染优化
利用好async和defer这两个属性:如果是独立功能的js文件,可以加入async属性。如果是优先级低且没有依赖的js,我们可以加入defer属性。
使用ssr渲染:服务器性能一般都很好,那么可以先在服务器先把vdom计算完成后,再输出给前端,这样可以节约的时间为:计算量/(服务器计算速度 - 客户端计算速度)。第二个是服务器可以把首屏的ajax请求在服务端阶段就完成,这样可以省去和客户端通过tcp传输的时间。
拆分接口,页面分批渲染,部分接口数据做localstorage缓存
图片优化
选择先进的图片格式:使用 JPEG 2000, JPEG XR, and WebP 的图片格式来代替现有的jpeg和png,当页面图片较多时,这点作用非常明显。把部分大容量的图片从BaseLine JPEG切换成Progressive JPEG(理解这两者的差别)也能缩小体积。
jpeg 有损压缩,体积小,不支持透明。
png 无损压缩,高保真,支持透明。
png - 8 2 ^ 8种色彩 256种
png - 24 2 ^ 24种色彩 1600w种
png - 32 2 ^ 24 ^ 8种 (还有8种透明度色彩通道)
颜色支持越多,体积越大
svg 矢量图 体积小 不失真,适用于小图标
base64 减小http请求,但不宜处理大图片,因为大图片增加页面大小,webpack的url - loader已经支持
webP 新兴格式,支持有损和无损压缩,支持透明,体积还特别小,与 PNG 相比,通常提供 3 倍的文件大小,浏览器兼容性低,局限性较大。
项目中的支持webp(参照自京东gaea): 在index.html中判断是否支持webP
window.supportWebp = false;
if (document.createElement('canvas').toDataURL('image/webp').indexOf('data:image/webp') == 0) {
document.body.classList.add('webp');
window.supportWebp = true;
}
css中写两套样式,比如
.banner{ background - image: url("xxxx.png") }
.webp .banner{ background - image: url("xxxx.webp") }
在js中根据window.supportWebp去判断用哪种图片。
页面性能测试工具
- PageSpeed Tools
- Lighthouse
- OneAPM
本文共 1428 个字数,平均阅读时长 ≈ 4分钟
111