有关web前端优化的博文,博客园中有许多网友的博客中都有介绍,并且详细、精准。楼主打算写这个博客,算是对本身一年工做来的一个总结和积累有些知识从别的地方拷贝过来的,可是都审查过。css
引言:html
1. 慢的页面可能会网站失去更多的用户.
2. 慢500ms意味着20%的用户将放弃访问(google)
3. 慢100ms意味着1%的用户将放弃交易(amazon)前端
经过上面列举的三个数据,能够看到web前端优化的重要性,而做为程序员,总有一股矫情劲,但愿将本身开发出来的东西能更加的完美。:)java
通常来讲,咱们从变化性上把数据分红两种类型,变和不变.那么不变的数据能够缓存,变化的数据不能缓存,这是一个常识,也就是说要减小咱们的http请求次数这个目标能够转换成把数据分为变化和不变化两个部分.不变化的数据不须要再次请求,这样http请求的次数就减小了,下面咱们分点来描述将数据分类的途径.程序员
包括脚本、样式文件和图片,能够有选择的把一些Js和css能够合并成一个文件,一些图片可使用css sprites技术。这样作的缘由是什么?作过web开发的人都知道,js和css基本是不变的,是静态文件,图片亦然。那么不变的文件若是适当的合并在一块儿,会有什么效果呢?请求的次数从屡次变成了一次,这样http请求的次数就减小了。其实对于js的合并更是尤其重要,咱们知道浏览器对js的加载是阻塞式的。什么意思呢,对于css和图片之类的,浏览器大多支持并行加载,由于浏览器加载DOM树时,检测到会先预留一个节点,进而进行下面的加载,而js中存在建立DOM节点的可能,因此加载js存在一个解析的过程。web
对于静态内容:设置文件头过时时间Expires的值为“Never expire”(永不过时) ajax
动态页面,在代码中添加cache-control,表示多少时间以后过时,如:
response.setHeader("Cache-Control", "max-age=3600");
若是使用了Expires文件头,当页面内容改变时就必须改变内容的文件名。一般是在文件内容后加版本号
这一点是大多数人都忽略得,以前不少人在坛子上发布本身得小系统,还有demo,ahuaxuan跑过去一看,my god,一堆又一堆得js,css,既没有恰当得合并,也没有设置过时时间.每次刷新页面都要从新下载这一堆又一堆的js,css.http请求那叫一个多啊.无谓了流量就这样产生了.
这一点在企业应用的系统中也时有发生.好比咱们使用extjs做为前端的技术,400多k啊,每打开一个页面都导入,下载这个js,够无聊的.那么童子们可能就要问了,静态文件为啥不用apache,lighttpd等呢,答,用了又怎么样,不设expire或者max-age不是同样要下载,最好的方法是写一个filter,再filter中判断,若是url知足必定的条件(好比符合配置文件中的正则表达式),那么就设置一个max-age,这样就ok,太简单了,几行代码就能够搞定.快哉.正则表达式
缓存的方法同动态页面,ajax请求须要使用get方式,url长度为2k(ie)限制(post请求有两个过程,1发送请求headers,2发送请求数据,根据http规范,get请求只会发送一个tcp包).--------这一段话来自yahoo,先无论其真假,咱们从另一个方面来考虑一下为何最好使用get方式,讲一个ahuaxuan经历过的事情,以前有一个项目的ajax请求使用了post方式,后来发现常常出错,并且抛出了squid的错误,由于咱们的网站使用了squid,问题就出在这里了,从http协议上能够了解到,method=post是指把数据提交到服务器上去,那么squid的一个特性是不会缓存post请求(事实上它确实不该该缓存,由于这样会违反http协议中的语义),把ajax请求改为get方式以后,一切恢复如常.apache
重复的js导入也有可能致使ie从新加载该脚本 。后端
有一种常常被网页开发者忽略却每每十分浪费响应时间的跳转现象。这种现象发生在当URL本该有斜杠(/)却被忽略掉时。这时候会返回一个301的状态码,而后浏览器从新发起一次请求.在企业应用里,重定向是咱们在企业应用中经常使用的技术,不过用在网站项目上,您可要当心了,由于普通的重定向实际上是server在response header中设置http status=302,浏览器收到以后,判断出是302,会从新发送一个请求,目标地址是前一次返回中指定的地址.在网站项目中若是能够不用重定向就别用吧.若是您作企业应用项目,ok,关系不大,您就放心的”定”吧.
小节,减小http请求次数分为了以上5个小点,每一个小点以后附加一些实例,你们能够根据这些点来判断本身的项目是否能够有优化的地方.
使用cdn
让内容更靠近用户,这有啥好说呢,原理很简单,就是根据用户浏览器所在机器的ip来判断哪些服务器离用户最近,浏览器会再次去请求这些最近的机器.通常的cdn服务商是经过开发本身的dns server来达到这个目的的.不过这个是一般状况哦,技术实力比较高,或者场景比较特殊的公司会开发本身的cdn.固然无论怎么说,使用cdn确定可使页面响应更快(也包括音频,视频,图片,文本文件,等等等等)
Gzip压缩全部可能的文件类型是减小文件体积增长用户体验的简单方法。好比原本400k的文件,压缩一下以后只有50k-100k,那么网络的流量就马上下来了,压缩的代价是服务器端要压缩文件,须要消耗cpu,浏览器须要解压文件,也须要消耗cpu,不过对于现代这么nb的pc,来讲,浏览器解压一下数据带来的cpu消耗简直不值一提.因此您就压吧.不过压的时候要当心哦,有的浏览器在特定场景下会出去一些小bug,致使页面不正常.好比ie6在跨域的时候可能会有些小麻烦,把这部分数据的gzip去掉就能够了.
压缩js可使用JSMin或者YUICompressor,后者同时能够压缩css,这个也没啥好说的,照作吧.有关YUI Compressor 这个,能够了解下,楼主试用过,不错。
其实这一点也能够当作是区分不变数据和变化数据.不少人喜欢在页面上写不少不少的js和css,这些数据其实都是不会变化的数据,也就是说这些数据也是能够缓存在浏览器上的,经过把它们独立成外部文件,能够把这些数据缓存起来.这样作看上去是增长的请求的次数,可是因为第一次请求以后该部分数据已经被缓存,因此第二次就无需再请求后端,减小了网络带宽的开销.
cookie是用于身份认证尤为是个性化等操做,它是在http的请求头中进行交换的,它体积越大,则响应越慢;
每3000字节的cookie在DSL的带宽中会增长80毫秒的响应;因此除去没必要要的cookie,已经使用短小的文件名和尽量小的减小cookie的大小都有利于改善响应时间。
因为二级域名能够拿到一级域名得cookie,那么若是,而二级域名之间确不能相互共享cookie,因此合理得设置cookie得域名也能够避免无必要得带宽浪费和响应速度得增长.
该过时就过时,不要让没必要要的数据一直带在身上走来走去.
为图片或者其余静态资源文件使用子域或者创建新的独立域名(申请新的域名),避免无必要的cookie传输,固然也是要在有必要得状况下,图片类网站确定有必要,javaeye上得图片并无使用域分离,因此咱们得cookie其实会带到坛子得图片服务器上去,每次请求图片都是如此(不过还好,坛子里没有什么图片,因此这方面的浪费不大).
小结,其实cookie上的问题,单次请求看上去也不是什么大问题,好像是无所谓得事情,就那么几十个byte,至于吗,不过你们都据说过水滴石穿,绳锯木断的故事.因此该作的,咱们仍是要作,正所谓,勿以善小而不为,勿以恶小而为之.
把样式表放在文档底部的问题是在包括Internet Explorer在内的不少浏览器中这会停止内容的有序呈现。浏览器停止呈现是为了不样式改变引发的页面元素重绘。用户不得不面对一个空白页面。
HTML规范清 楚指出样式表要放包含在页面的<head />区域内:“和<a />不一样,<link />只能出如今文档的<head />区域内,尽管它能够屡次使用它”。不管是引发白屏仍是出现没有样式化的内容都不值得去尝试。最好的方案就是按照HTML规范在文 档<head />内加载你的样式表。
脚本带来的问题就是它阻止了页面的平行下载。HTTP/1.1 规范建议,浏览器每一个主机名的并行下载内容不超过两个。若是你的图片放在多个主机名上,你能够在每一个并行下载中同时下载2个以上的文件。可是当下载脚本时,浏览器就不会同时下载其它文件了,即使是主机名不相同。
Js放在底部加载其实并不影响浏览器展现页面,除非用户会在js加载完成以前就调用某个js方法,好比说页面刚展示到一半,可是刚好这一半里有一部分是调用了还未下载的js,这个时候就会出问题了,若是童子们遇到这种状况,能够把这部分js先加载.
若是能够的话,将这些CSS和js都缓存在本地浏览器中,由于这些均可以考虑为静态文件。
咱们在不少地方用js输出一段html片断时一般会使用以下代码:
var _html = ""; _html = "<div style='padding-bottom: 5px'>"; _html += "<span class='icon_favorite' style='padding-top: 2px; padding-bottom: 2px'>这是js打印出来的</span>"; document.write(_html);
下面看看用join如何书写:
var _html = []; var i = 0; _html[i++] = "<div style='padding-bottom: 5px'>"; _html[i++] = "<span class='icon_favorite' style='padding-top: 2px; padding-bottom: 2px'>这是js打印出来的</span>"; document.write(_html.join(""));
或者使用push:
var _html = [];
_html.push("<div style='padding-bottom: 5px'>"); _html.push("<span class='icon_favorite' style='padding-top: 2px; padding-bottom: 2px'>这是js打印出来的</span>"); document.write(_html.join(""));
楼主看web性能指南中有提到,这种写法更高效。
低效率:
//效率低的 function GetDivNum() { var divs = document.getElementsByTagName("div"); var start = new Date().getTime(); for (var i = 0; i < divs.length; i++) { //"效率低" } var end = new Date().getTime(); alert("用时:" + (end - start) + "毫秒"); }
高效率:
//效率高的 function GetDivLen() { var divs = document.getElementsByTagName("div"); var start = new Date().getTime(); for (var i = 0, len = divs.length; i < len; i++) { //"效率高" } var end = new Date().getTime(); alert("用时:" + (end - start) + "毫秒"); }
缘由:
主要是由于for循环在执行中,第一种状况会每次都计算一下长度,而第二种状况倒是在开始的时候计算长度,并把其保存到一个变量中,因此其执行效率要高点,因此在咱们使用for循环的时候,特别是须要计算长度的状况,咱们应该开始将其保存到一个变量中。可是并非只要是取长度都会出现如此明显的差异,若是咱们仅仅是操做一个数组,取得的是一个数组的长度,那么其实两种方式的写法都差很少。这里再也不测试了。
OK,先总结道这里,下篇介绍前端优化结合后台的一些操做,主要简介如何实现js的合并以及压缩输出。