浅谈WEB页面提速(前端向) - vajoy

标签: web 页面 前端 | 发表时间:2014-12-27 14:19 | 作者:vajoy
出处:

记得面试现在这份工作的时候,一位领导语重心长地谈道——当今的世界是互联网的世界,IT企业之间的竞争是很激烈的,如果一个网页的加载和显示速度,相比别人的站点页面有那么0.1秒的提升,那也是很大的一个成就。

然后我不知道怎么写下去了,就在群里问了那群狗头军师,结果是这样的。。。

好的,是时候“语锋一转”切回主题了 —— 如何提升我们站点页面的访问速度、减少等待时间,从而最大化地提升用户访问体验呢?

针对这个问题,我们今天会从前端的角度来提出系列解决方案,它们都能有效地提升你页面的访问速度。

一. 减少对服务器的文件请求

常规的HTTP请求属于“请求”-“应答”-“断开”形式的短连接,每一个独立的资源我们都会向服务器发去一份get请求,再等服务端将我们需要的文件传回来。每一次资源的请求都实实在在地耗费了一次“连接-等待-接收”的时间(当然将http请求设为keep-alive长连接状态可以减少“连接”的次数和时间),如果我们能有效减少对服务器文件的请求次数,便意味着我们可以从这块省下一些页面等待时间,也可以顺便减少服务器的负担。

对于这个解决方案,我们可以这么做:

1. 使用css sprite技术合并多个图片为单个图片文件,实际使用时通过background-position来定位背景位置(相信大家第一个想到的也是这个吧);

2. 合并多个css样式文件为单个样式文件,合并多个脚本为单个脚本,再在页面中引用合并后的样式/脚本文件。对于这个你可以使用r.js来帮忙( 看我这篇文章),但我个人倒是不怎么推荐这个方法,因为合并了文件之后,多个页面之间公共部分的样式/脚本文件就无法缓存到客户端了;

3. 使用base64编码来展示图片。就如图github 404页面那样:

你可以使用 这个工具来帮你把图片转换为base64编码的文件流,但常规只推荐你把这种方式使用在用户重复访问量较少的页面,因为它们虽然无须从服务端get一遍,但也无法缓存在客户端,导致用户每次访问页面都要重新渲染一次。而且冗长的文件流代码会占用你页面很大的代码空间,维护起页面来估计也会挺心塞;

4. 将小块的css、js代码段直接写在页面上,而非在页面引入独立的样式/脚本文件。相信有的朋友看惯了“保持结构 (标记)、表现 (样式)、行为 (脚本)三者分离”的规范,对此观点可能有些意见。只能说规范不是教条,适合自己的才是硬道理。直接把小段的、复用率低的样式/脚本直接写于页面上带来的利还是大于弊的(弊可能也就是增大了页面代码量、不那么好维护了点)。反观所有主流门户网站的页面源文件,基本没有一个是把样式/脚本都全部作为外部文件引入的(无论他们是否从减少服务器请求这点出发,事实都是这样);

5. 利用http-equiv="expires"元标签,设定一个未来的某时间点作为页面文件过期时间,用户在过期时间之前所获取到的页面文件都仅从缓存中去取。不过这个办法太死板(有时候即使服务端及时把过期时间更改为已结束时间,客户端可能都不会按照新更改的规则去服务端获取新文件资源),常规是不推荐使用的。

二. 减少文件大小

文件太大(特别是图片)导致加载时间较长,往往都是影响页面加载体验的头号大敌,那么尽可能减少请求文件的大小便是相当重要的事情了,我们可以做的事情有:

1. 压缩样式/脚本文件,就此你可以使用 gulp或者 grunt来实现这点,它们均能很好地减少css/js文件的大小(对于js还能起到混淆变量、函数名的作用);

2. 针对性选择图片格式,在无透明背景需求下,对于颜色较单一、无色彩渐变的图片仅使用gif格式,对于jpg图片也可按照其清晰度要求,在导出jpg的时候选择对应的“品质”进行优化:

如果你喜欢尝鲜,可以学淘宝那样使用webp图片格式,它能很好地优化同画质下的文件大小:

如果你对webp感兴趣,可以 查阅这里

3. 使用 Font Awesome来替代页面上的图标,其原理是使用@font-face让用户下载一个非常小的UI字体包,把页面上用到的图标以字符的形式来显示,从而减少了图片需求和图标文件大小。

三. 适度使用CDN

使用CDN有几个好处:如果用户在其它站点下载过这个CDN资源,那么来我们站点仅仅从缓存获取即可;减少了对自己站点服务器的文件请求(外部CDN的情况下),减少服务器负担;多个域会使浏览器允许异步下载资源的最大数量增多,比如一个站点只从一个域来请求资源,那么FireFox只允许同时刻最多异步下载2个文件,但如果使用了外部CDN来引入资源,那么FF允许在同时异步下载本域中的两个资源外,还额外允许同时异步下载另一个域(CDN)下的2个资源。

但是使用CDN有一个很大的问题——增加了dns解析的开销,如果一个页面同时引入了多个CDN的资源,可能会因为dns解析而陷入较多的等待时间,导致得不偿失。

对于这个问题,常规是建议一个站点下只使用同一个可靠、快速的CDN来引入各种所需资源即可,也就是说,建议一个页面从2个不同的域(比如站点域和CDN域)下来请求资源是最佳的选择(据说这个结论是雅虎前端工程师提出的, 这里有一篇很不错的文章)。

四. 延迟请求、异步加载脚本

在各主流浏览器下,常规情况,我们的脚本文件跟随其它资源文件一样都是异步下载的,但这里存在一个问题——比如FireFox下载好脚本后的一小段时间内会有“执行阻塞”的情况发生,也就是说浏览器下载好脚本后执行它的这段时间里,浏览器的其它行为被阻塞,导致页面上的其它资源都是无法被请求和下载的:

如果你页面里存在js代码执行时间过长的情况,那么用户就会明显感觉到页面的延迟。解决这个问题有一个简单的方法——将脚本请求标签放置到</body>结束标签前,使得页面上的脚本成为最后被请求的资源,自然也不会阻塞其它页面资源的请求事件了。

另外,虽然上面提到“我们的脚本文件跟随其它资源文件一样都是异步下载的”,但异步下载不代表异步执行,为了严格保证脚本逻辑顺序和依赖关系的正确性,浏览器会按照脚本被请求的先后顺序来执行脚本。那么问题就来了——如果页面上的脚本依赖关系并不大,甚至没有任何相互间的依赖,那么浏览器的这套规则就仅仅增加了页面请求阻塞时间而已(就像你花大钱买了一笔保险,但被保险期间你平安无事啥都没发生。。。嗯,这个比喻有点反人类。。。)。

解决这个问题的办法无非就是让脚本无阻塞地异步执行,比如给script标签加上defer和async属性或者动态注入脚本(可以参考 这里),但这些都不是良好的解决方案,要么存在兼容性问题,要么太麻烦还无法处理依赖。

个人是推荐使用 requireJS(AMD规范) 或 seaJS(CMD规范) 来异步加载脚本并处理模块依赖的,前者将“依赖前置”(预加载所有被依赖脚本模块,执行速度最快),后者走的“依赖就近”(懒加载被依赖脚本模块,请求脚本更科学),你可以根据项目具体需求来选择最合适的。

五. 延迟请求首屏外的文件

先解释下,“首屏”指的是页面初始化时候的页面内容显示区域,也就是页面一加载,用户就首先看到的区域。

比如像京东啊淘宝啊,对于需要滚动页面才能看到的图片内容,都做了类似lazyload的处理,这些无非都是走了代理模式的理念,但的确给用户一个错觉——这个页面更快地加载完了,因为我很快就看到了屏幕上的内容(即使我还没下拉滚动条,而页面后方的文件其实还没真正加载呢)。

我们可以这样实现此方案,不依赖任何lazyload库,拿图片来做示范,我们可以这样编写首屏外的图片(假设某张图片地址是a.jpg)的img标签:

<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="a.jpg">

如上所示,页面初步加载这张图片的时候是直接以base64的方式(当然你也可以统一使用一张占位图loading.gif来替代)来快速显示一张极小的图片的,而图片本身的真实路径是存在data-src属性内的,我们可以在页面加载结束后再向服务器请求它真实的文件并替换:

function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
}
}
}
window.onload = init;

如上是对图片的延迟加载处理,对于视频、音频文件,可以采取完全一样的原理来延迟加载,从而有效减少页面初始化等待时间。

六. 优化页面模块排放顺序

这里有一个很好的例子,比如有一个页面是这样的——左边是侧边栏,用于存放用户的头像啊、资料啊,以及网站投放的广告啊,而右侧是文章内容区域:

那么我们的代码很可能是这样的:

<body>
<sidebar>
<!-- 侧边栏内容 -->
</sidebar>

<content>
<!-- 文章内容 -->
</content>
</body>

于是乎,浏览器按照它的UI单线程准则从上到下先加载了侧边栏,再加载我们的文章。。。

很明显,这样不是一个人性化的加载顺序, 我们得弄清楚,页面上各个区域模块,对于用户而言,哪个才是最重要、最应当首先展示的

对于上面的例子,文章内容才应该是用户首先要看到、需要浏览器优先请求和显示的区域。所以我们得修改我们的代码为:

<body>
<content>
<!-- 文章内容 -->
</content>

<sidebar>
<!-- 侧边栏内容 -->
</sidebar>
</body>

当然这里仅仅是用一个小示例来挑起各位的脑洞,懂得举一反三和实际运用才是硬道理。

七. 其它建议

1. 不要在css中使用@import,它会让一个样式文件去等待另一个样式文件的请求,无形中增加了页面等待时间(当然如果走的scss,@import就是另一回事了,呃跑题了~);

2. 避免页面或者页面文件重定向查找,这相当于你走进了一间卫生间,然后看到上面的牌子说“此处不同,请去前面左拐的卫生间”,又得重走一遍;

3. 减少无效请求——比如通过css/js来请求一个不存在的资源,可能会导致较长的等待和阻塞(直到它返回错误信息);

4. 配置.htaccess文件、走Gzip压缩页面形式、开启keep-alive连接模式等后端解决方案,这边就不细说了。

相信页面提速的方案绝对不仅仅局限于上面提到的这些,而且每个项目都有着各种需求和情况,只能按需选择适合自己的方案。

但最重要的还是——尽量把用户的体验放在第一位,无论是页面的加载或者交互,都应当多从用户角度切入去思考和设计最优选的方案,这样相信你一定能做出出色、受欢迎的作品。

今天聊的就是这些,共勉~


本文链接: 浅谈WEB页面提速(前端向),转载请注明。

相关 [web 页面 前端] 推荐:

浅谈WEB页面提速(前端向) - vajoy

- - 博客园_首页
记得面试现在这份工作的时候,一位领导语重心长地谈道——当今的世界是互联网的世界,IT企业之间的竞争是很激烈的,如果一个网页的加载和显示速度,相比别人的站点页面有那么0.1秒的提升,那也是很大的一个成就. 然后我不知道怎么写下去了,就在群里问了那群狗头军师,结果是这样的. 好的,是时候“语锋一转”切回主题了 —— 如何提升我们站点页面的访问速度、减少等待时间,从而最大化地提升用户访问体验呢.

Web前端优化

- - JavaScript - Web前端 - ITeye博客
优点:直接使用浏览器内存的缓存数据,减少网站后台压力,用户体验(速度)好. 缺点:对于时时变化的动态页面,这种情况就不能容忍了,因为每次访问的都是第一次访问的内容,这样即使所请求的页面已经变化了,用户也不可能知道,所以此场景必须要消除这种缓存的影响. 延迟加载,将资源延迟到需要的时候的加载,例如detail页面,相关产品推荐,当用户浏览更多的信息往下拉动滚动时,才进行加载,异步加载可以大幅减少对后端资源的使用,在需要的时候加载,是资源合理使用常用的方式,但是也带来一个问题,当往下拉才去加载,如果性能不够好,用户的体验其实是不好的,“菊花”转动的时间会比较长,同时异步加载对前端性能的作用也是非常明显的,渲染的节点数量大幅减少.

Web 前端测试

- - Web前端 - ITeye博客
Web 网站测试流程和方法(转载). 进行正式测试之前,应先确定如何开展测试,不可盲目的测试. 一般网站的测试,应按以下流程来进行:. 1)使用HTML Link Validator将网站中的错误链接找出来;. 2)测试的顺序为:自顶向下、从左到右;. 3)查看页面title是否正确. (不只首页,所有页面都要查看);.

Web页面入门

- - 可咔酷 | 网络杂货铺
开发页面在很多人眼里很简单,大部分的人都会说不就是把效果图变成网页嘛,哪里需要那么多的时间,一点技术含量都没有. 确实html页面没有js那么多复杂的交互,也不需要和后台数据打交道,但并不能代表就没有技术含量,也不是人人都能做好的. 页面结构好坏直接会影响到css代码的质量,也会影响js和后台的开发,还会影响到以后功能的扩展和代码的优化.

Web 前端攻防(2014版)

- - 博客 - 伯乐在线
外链会产生站外请求,因此可以被利用实施 CSRF 攻击. 目前国内有大量路由器存在 CSRF 漏洞,其中相当部分用户使用默认的管理账号. 通过外链图片,即可发起对路由器 DNS 配置的修改,这将成为国内互联网最大的安全隐患. 百度旅游在富文本过滤时,未考虑标签的 style 属性,导致允许用户自定义的 CSS.

Web 页面测试点

- - Web前端 - ITeye博客
(1) 页面清单是否完整(是否已经将所需要的页面全部都列出来了). (2) 页面是否显示(在不同分辨率下页面是否存在,在不同浏览器版本中页面是是否显示). (3) 页面在窗口中的显示是否正确、美观(在调整浏览器窗口大小时,屏幕刷新是否正确). (4) 页面特殊效果(如特殊字体效果、动画效果)是否显示.

Web前端优化最佳实践

- Jimmy - 中文热文榜|最新
还有 Jason, Bixuan, 曦, 推荐,查看全部 8 个推荐. 博评 - Sting的网经发表于2010-08-08 08:41:10. Google的前端优化最佳实践 Yahoo的前端优化最佳实践. Web前端优化最佳实践之Content篇. 尽量减少 HTTP 请求 (Make Fewer HTTP Requests).

Web前端浏览器兼容初探

- - 博客 - 伯乐在线
浏览器兼容是前端开发人员必须掌握的一个技能,但是初入前端的同学或者其他后台web开发同学往往容易选择忽略,而形成两个极端:. 1 我最开始都是使用IE6,IE6上没问题,其它浏览器坑爹(多出现与前端后端一起搞的同学,小生2年前就这种状态,鼓励人家用ie6.. 2 我要遵循标准,我只要ff就好,IE就是坑爹的玩意,我不必去理他(小生一年前的心态.

web前端性能优化进阶路

- - 阿里巴巴(中国站)用户体验设计部博客
Web前端性能优化WPO,相信大多数前端同学都不会陌生,在各自所负责的站点页面中,也都会或多或少的有过一定的技术实践. 可以说,这个领域并不缺乏成熟技术理论和技术牛人:例如Yahoo的web站点性能优化 黄金法则,以及大名鼎鼎的优化大师 Steve Souders. 本文并非一篇讨论性能优化技术方法的文章,而更多的是对中文站 搜索List页面持续两年多的前端性能优化实践的 思路总结.

web前端面试笔试题+优化

- - JavaScript - Web前端 - ITeye博客
前端是庞大的,包括HTML、CSS、Javascript、Image、Flash等等各种各样的资源. 前端优化是复杂的,针对方方面面的资源都有不同的方式. 那么,前端优化的目的是什么. 从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验. 从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源.