Web性能优化 | 如何提高首屏加载速度?

在 FrontJS 的使用反馈中,页面和资源的加载速度是很多用户密切关注的数据,想要提高加载速度,就需要不断的对网站进行优化。相信大家都有在浏览网页时遇到过页面加载不完全的问题。作为网站的“建造人”,我们不仅是开发者,同时也是用户。当我们在网页上看到各种红叉和长时处于 loading 状态的信息时,会瞬间失去浏览页面的兴致,变得不耐烦起来——尤其是首屏,加载的快与慢直接影响着用户的使用体验及滞留时间。

相对于移动端的首屏,Web端想让用户看到的信息更多更丰富,页面难免会大而“重”,首屏作为用户与网站的第一眼互动,“秒开”变得至关重要。今天就来谈谈如何对首屏时间进行性能优化。

  • 什么是首屏?

以800×600像素尺寸为标准,当浏览器加载页面后看到第一眼的显示内容为首屏;从开始加载到浏览器页面显示高度达到600像素且此区域有内容显示的时间为首屏显示时间(当然这个标准随着技术进步在不断变化)下图京东首页为例,对于电商网站而言,营销活动的banner、轮播图、账户信息、分类检索等供用户自主选择的主要内容全部集中在首屏,所以对首屏的加载速度要求极高。

  • 大公司是如何进行首屏优化的?

仍然以京东为例:

当我们打开京东的网站(不要滚动鼠标和键盘),右键查看源代码会发现京东首页的DOM树出奇的简单,页面DOM中多含有mod_lazyload的类。

<div class="J_f J_lazyload J_f_lift mod_lazyload need_ani chn" id="portal_8" data-backup="basic_8" data-source="cms:basic_8" data-tpl="portal_tpl">

再看下 localstorage

尤其在查看键名类似于 URL 的键值对时,会发现它们的值中多存在一串完整的类似于html的内容。

{"dom":"{%var liftTxtArr = pageConfig.liftTxtArr,clstagPrefix = 'h|keycount|2016|41a', i;%}<ul class=\"lift_list\">{% for (i = 0; i < liftTxtArr.length; i++) { %}<li class=\"J_lift_item lift_item{%= (i===0) ? ' lift_item_first' : '' %}\" clstag=\"{%= clstagPrefix + (i < 9 ? '0' : '') + (1+i) %}\"><a href=\"javascript:;\" class=\"lift_btn\"><span class=\"lift_btn_txt\">{%= liftTxtArr[i] %}</span></a></li>{% } %}<li class=\"J_lift_item J_lift_item_top lift_item lift_item_top\" clstag=\"{%= clstagPrefix + (i < 9 ? '0' : '') + (1+i) %}\"><a href=\"javascript:;\" class=\"lift_btn\"><span class=\"lift_btn_txt\">顶部<i class=\"lift_btn_arrow\"><!--&#xe606;--></i></span></a></li></ul>","style":".lift{display:none;position:fixed;z-index:100;-moz-box-shadow:0 0 4px rgba(0,0,0,.2);box-shadow:0 0 4px rgba(0,0,0,.2);background-color:#918888}.lift_item{border-top:1px solid #b1aaaa;-webkit-transition:background-color .1s;-moz-transition:background-color .1s;transition:background-color .1s}.lift_item_first{border-top:none}.lift_btn{*cursor:pointer;overflow:hidden;display:block;width:24px;padding:10px 5px;line-height:14px;text-align:center;color:#fefefe;-webkit-transition:color .1s;-moz-transition:color .1s;transition:color .1s}.lift_item:hover,.lift_item_on{position:relative;border-bottom:1px solid #d70b1c;margin-bottom:-1px;border-color:#d70b1c;background-color:#d70b1c}.lift_item:hover .lift_btn,.lift_item_on .lift_btn{color:#fff}.lift_item_top,.lift_item_top:hover{border-top:1px solid #f6f6f6;background-color:#5e4a4a;border-bottom:0;margin-bottom:0}.lift_item_top .lift_btn{color:#fff}.lift_btn_arrow{display:block;width:0;height:0;margin:auto;border-style:solid;border-width:4px;border-color:#5e4a4a #5e4a4a #fff}.o2_mini .lift{display:none}","version":"062a40dffff4da26"}

由上面的结构可知,京东已经将它们的页面结构放到了localstorage。由此可见,只是它页面其中一个模块的内容。分析到这里已经很明显了,京东通过前端缓存和异步加载已经完美的实现了首屏快速加载,在Web端达到了秒开的级别。

京东首先只加载框架然后将框架内容与模版绑定,用户滚动时,一旦该框架内容部分进入了视窗,则请求对应的 data-tpl 地址,拿到渲染这个模块所需要的脚本和数据,不过这中间还有一层本地缓存 localstorage,如果在本地缓存中匹配到了对应的 hash string 内容,则直接渲染,否则请求到数据之后更新本地缓存。localstorage 中的 version 会在页面加载时候,与后端文件 hash相对比,hash不变直接取localstorage中的内容(当然也可以使用cookie判断版本)。

如果数据和初始化脚本包装在一起,虽然节约了一个请求,但一旦数据变化,整个脚本都得重新加载。将数据和脚本分离,脚本可以长期缓存在本地,单独请求数据,这个量会小很多。直接改变上面的 version 版本号便可以让浏览器重新请求最新脚本。

从上面可以看出,任何一个模块的改动,在前端只会引起一个较小的加载变化,加上 http 的缓存策略,服务器的压力也是很小的。

看了上面的内容,相信大家已经对京东关于首屏优化的方案有了一个大致的了解,下面我们再整理一下关于首屏显示速度优化细节上的内容:

  • CSS静态文件在哪里?

为了追求速度,京东的首页是没有 CSS 外链的,相信对于我们来说,也是老生常谈的前端优化了。

有人可能会问,如果没有 CSS 外链,那一整个页面的 CSS 是否会增加页面的体积?其实上面已经提到,将页面切分为模块化加载,对应模块下的 CSS 交给 js 或 jsonp 请求返回。

  • js文件怎么加载?

如果外部 CSS 资源较小,可以直接将这些内容插入到HTML文档中,这称为“内嵌”。通过这种方式内嵌较小 CSS 资源,浏览器可以继续呈现网页。请注意,如果CSS文件较大,完全内嵌CSS可能会对浏览器构建和渲染DOM树增加不少压力。如果 CSS 文件较大,您需要识别和内嵌呈现首屏内容所需的 CSS,并暂缓加载其余样式,直到首屏内容显示之后为止。

京东采用请求的方式减少了与服务器交互的时间。

<script src="//misc.360buyimg.com/??/jdf/lib/jquery-1.6.4.js,/jdf/2.0.0/ui/ui/1.0.0/ui.js,/mtd/pc/index/gb/lib.min.js,/mtd/pc/base/1.0.0/base.js,/mtd/pc/common/js/o2_ua.js,/mtd/pc/index/home/index.min.js,/mtd/pc/index/home/init.min.js"></script>
  • js文件怎么执行?

懒加载也就是延迟加载,有交互才执行。js文件有需要时才加载,并不是再打开页面时一次性全部加载完成。

  • 图片如何处理?

图片在其他屏(非首屏)都采用懒加载的模式,这样既能节省流量,也能减少请求数或延迟请求数。

当访问一个页面的时候,先把 img 元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。用这样的方式,可以使页面加载速度变快,从而减轻服务器的压力,同时优化用户体验。当访问一个页面的时候,先把 img 元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。用这样的方式,可以使页面加载速度变快,从而减轻服务器的压力,同时优化用户体验。

  • 服务器需要做什么?
  1. 少量静态文件的域名,图片与iconfont均是放在同一个域下,减少DNS的解析事件,最好做到域名收敛。
  2. 模块化接口的支持。
  3. 首屏内容最好做到静态缓存。

版权声明:

*本文在转载时有删改

原作者:一半水一半冰

出处:https://www.cnblogs.com/jingh/p/6531105.html#3962455