毫秒必争,前端网页性能最佳实践javascript
你愿意为打开一个网页等待多长时间?我一秒也不肯意等。可是事实上大多数网站在响应速度方面都让人失望。如今愈来愈多的人开始创建本身的网站,博客,你的网页响应速度如何呢?在这篇文章中咱们来介绍一下提升网页性能的最佳实践,以及相应的问题解决方案,让站长或者即将要成为站长的朋友了解如何去测试和提升网站响应速度,对本身的网站更有信心。css
最佳实践html
最佳实践咱们引用的来自yahoo前端性能团队总结的35条黄金定律。原文猛击这里。下面咱们分门别类将每条的关键点总结一下。前端
网页内容java
减小http请求次数web
减小DNS查询次数ajax
避免页面跳转express
缓存Ajax浏览器
延迟加载缓存
提早加载
减小DOM元素数量
根据域名划份内容
减小iframe数量
避免404
服务器
使用CDN
添加Expires 或Cache-Control报文头
Gzip压缩传输文件
配置ETags
尽早flush输出
使用GET Ajax请求
避免空的图片src
Cookie
减小Cookie大小
页面内容使用无cookie域名
CSS
将样式表置顶
避免CSS表达式
用<link>代替@import
避免使用Filters
Javascript
将脚本置底
使用外部Javascirpt和CSS文件
精简Javascript和CSS
去除重复脚本
减小DOM访问
使用智能事件处理
图片
优化图像
优化CSS Sprite
不要在HTML中缩放图片
使用小且可缓存的favicon.ico
移动客户端
保持单个内容小于25KB
打包组建成符合文档
网页内容
减小http请求次数
80%的响应时间花在下载网页内容(images, stylesheets, javascripts, scripts, flash等)。减小请求次数是缩短响应时间的关键!能够经过简化页面设计来减小请求次数,但页面内容较多能够采用如下技巧。
1. 捆绑文件: 如今有不少现成的库能够帮你将多个脚本文件捆绑成一个文件,将多个样式表文件捆绑成一个文件,以此来减小文件的下载次数。例如在asp.net中可使用ScriptManager,asp.net MVC中的Bundling。
2. CSS Sprites: 就是把多个图片拼成一副图片,而后经过CSS来控制在什么地方具体显示这整张图片的什么位置。给你们看个熟悉的Sprites实例。
豆瓣把他的图标集中在一块儿,而后咱们看他如何控制只显示第一个图标的
.app-icon-read {
background-position
: 0 0;
}
.app-icon {
background
: url("/pics/app/app_icons_50_5.jpg") no-repeat scroll 0 0 transparent;
border-radius: 10px 10px 10px 10px;
box-shadow: 1px 1px 2px #999999;
display: inline-block;
height
: 50px;
width
: 50px;
}
3. Image Maps: 也是将多幅图拼在一块儿,而后经过坐标来控制显示导航。这里有个经典的例子,选中图片中的某我的就会将你带到不一样的连接。
4. Inline images: 经过编码的字符串将图片内嵌到网页文本中。例以下面的inline image的显示效果为一个勾选的checkbox。
.sample-inline-png {
padding-left: 20px;
background: white url('data:image/png;base64,iVBORw0KGgoAA
AANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0l
EQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6
P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC') no-repeat scroll left top;
}
图片显示效果如左图
减小DNS查询次数
DNS查询也消耗响应时间,若是咱们的网页内容来自各个不一样的domain (好比嵌入了开放广告,引用了外部图片或脚本),那么客户端首次解析这些domain也须要消耗必定的时间。DNS查询结果缓存在本地系统和浏览器中一段时间,因此DNS查询通常是对首次访问响应速度有所影响。下面是我清空本地dns后访问博客园主页dns的查询请求。看少去还很多哦。
避免页面跳转
当客户端收到服务器的跳转回复时,客户端再次根据服务器回复中的location指定的地址再次发送请求,例如如下跳转回复。
HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html
当客户端遇到这种回复的时候,用户只能等待客户端再次发送请求,有的网站甚至会一直跳n次,跳到他想带你去的地方…固然在这个时候用户看不到任何页面内容,只有浏览器的进度条一直在刷新。
缓存Ajax
Ajax能够帮助咱们异步的下载网页内容,可是有些网页内容即便是异步的,用户仍是在等待它的返回结果,例如ajax的返回是用户联系人的下拉列表。因此咱们仍是要注意尽可能应用如下规则提升ajax的响应速度。
添加Expires 或 Cache-Control报文头使回复能够被客户端缓存
压缩回复内容
减小dns查询
精简javascript
避免跳转
配置Etags
延迟加载
这里讨论延迟加载须要咱们知道咱们的网页最初加载须要的最小内容集是什么。剩下的内容就能够推到延迟加载的集合中。
Javascript是典型的能够延迟加载内容。一个比较激进的作法是开发网页时先确保网页在没有Javascript的时候也能够基本工做,而后经过延迟加载脚原本完成一些高级的功能。
提早加载
与延迟加载目的相反,提早加载的是为了提早加载接下来网页中访问的资源,下面是提早加载的类型
无条件提早加载:当前网页加载完成后,立刻去下载一些其余的内容。例如google会在页面加载成功以后立刻去下载一个全部结果中会用到的image sprite。
有条件加载:根据用户的输入推断须要加载的内容,雅虎的示例是search.yahoo.com,
有预期的的加载:这种状况通常发生在网页从新设计时,因为用户常常访问旧网页,本地对旧的网页内容缓存充分从而显得旧网页速度很快,而新的网页内容却没有缓存,设计者能够在旧网页的内容中预先加载一些新网页中可能用到的内容,这样新的网页就会生下来一些须要下载的资源。
减小DOM元素数量
网页中元素过多对网页的加载和脚本的执行都是沉重的负担,500个元素和5000个元素在加载速度上会有很大差异。
想知道你的网页中有多少元素,经过在浏览器中的一条简单命令就能够算出,
document.getElementsByTagName('*').length
多少算是多了呢?雅虎在写这篇文章的时候号称主页只有700多元素,但如今接近多了一倍。咱们的网页至少别比雅虎还多吧。。。
根据域名划份内容
浏览器通常对同一个域的下载链接数有所限制,按照域名划分下载内容能够浏览器增大并行下载链接,可是注意控制域名使用在2-4个之间,否则dns查询也是个问题。
通常网站规划会将静态资源放在相似于static.example.com,动态内容放在www.example.com上。这样作还有一个好处是能够在静态的域名上避免使用cookie。后面咱们会在cookie的规则中提到。
减小iframe数量
使用iframe要注意理解iframe的优缺点
优势
能够用来加载速度较慢的内容,例如广告。
安全沙箱保护。浏览器会对iframe中的内容进行安全控制。
脚本能够并行下载
缺点
即便iframe内容为空也消耗加载时间
会阻止页面加载
没有语义
避免404
404咱们都不陌生,表明服务器没有找到资源,咱们要特别要注意404的状况不要在咱们提供的网页资源上,客户端发送一个请求可是服务器却返回一个无用的结果,时间浪费掉了。
更糟糕的是咱们网页中须要加载一个外部脚本,结果返回一个404,不只阻塞了其余脚本下载,下载回来的内容(404)客户端还会将其当成Javascript去解析。
服务器
使用CDN
再次强调第一条黄金定律,减小网页内容的下载时间。提升下载速度还能够经过CDN(内容分发网络)来提高。CDN经过部署在不一样地区的服务器来提升客户的下载速度。若是你的网站上有大量的静态内容,世界各地的用户都在访问,我说的是youtube么?那CDN是必不可少的。事实上大多数互联网中的巨头们都有本身的CDN。咱们本身的网站能够先经过免费的CDN供应商来分发网页资源。
添加Expires 或Cache-Control报文头
这条规则分为两个方面,
对于静态内容添加Expires,将静态内容设为永不过时,或者很长时间之后。在IIS中设置Expires能够看Configure the HTTP Expires Response Header (IIS 7)。
对于动态内容应用合适的Cache-Control,让浏览器根据条件来发送请求。关于asp.net的caching,能够看asp.net cache feature和asp.net caching best practices。
Gzip压缩传输文件
Gzip一般能够减小70%网页内容的大小,包括脚本、样式表、图片等文件。Gzip比deflate更高效,主流服务器都有相应的压缩支持模块。
IIS中内建了静态压缩和动态压缩模块,如何配制能够参考Enable HTTP Compression of Static Content (IIS 7)和Enable HTTP Compression of Dynamic Content (IIS 7)。
值得注意的是pdf文件能够从须要被压缩的类型中剔除,由于pdf文件自己已经压缩,gzip对其效果不大,并且会浪费CPU。
配置ETags
虽然标题叫配制ETags,可是这里你要根据具体状况进行一些判断。首先Etag简单来讲是经过一个文件版本标识使得服务器能够轻松判断该请求的内容是否有所更新,若是没有就回复304 (not modified),从而避免下载整个文件。
可是Etags的版本信息即便主流服务器未能很好地支持跨服务器的判断,好比你从一个服务器集群中一台获得Etags,而后发送到了另外一台那么校验颇有可能会失败。
若是你遇到这样的问题,IIS 7中能够经过以下方法将Etag去掉,使用URL Rewrite,而后在web.config中添加以下配制
<rewrite>
<outboundRules>
<rule name="Remove ETag">
<match serverVariable="RESPONSE_ETag" pattern=".+" />
<action type="Rewrite" value="" />
</rule>
</outboundRules>
</rewrite>
IIS8里提供了一个简单配制来直接关闭Etag,
<element name="clientCache">
<attribute name="cacheControlMode" type="enum" defaultValue="NoControl">
<enum name="NoControl" value="0" />
<enum name="DisableCache" value="1" />
<enum name="UseMaxAge" value="2" />
<enum name="UseExpires" value="3" />
</attribute>
<attribute name="cacheControlMaxAge" type="timeSpan" defaultValue="1.00:00:00" />
<attribute name="httpExpires" type="string" />
<attribute name="cacheControlCustom" type="string" />
<attribute name="setEtag" type="bool" defaultValue="false" />
</element>
尽早flush输出
网页后台程序中咱们知道有个方法叫Response.Flush(),通常咱们调用它都是在程序末尾,但注意这个方法能够被调用屡次。目的是能够将现有的缓存中的回复内容先发给客户端,让客户端“有活干”。
那在何时调用这个方法比较好呢?通常状况下咱们能够在对于须要加载比较多外部脚本或者样式表时能够提早调用一次,客户端收到了关于脚本或其余外部资源的连接能够并行的先发请求去下载,服务器接下来把后续的处理结果发给客户端。
使用GET Ajax请求
浏览器在实现XMLHttpRequest POST的时候分红两步,先发header,而后发送数据。而GET却能够用一个TCP报文完成请求。另外GET从语义上来说是去服务器取数据,而POST则是向服务器发送数据,因此咱们使用Ajax请求数据的时候尽可能经过GET来完成。
关于GET和POST的详细对比能够查看这里。
避免空的图片src
空的图片src仍然会使浏览器发送请求到服务器,这样彻底是浪费时间,并且浪费服务器的资源。尤为是你的网站天天被不少人访问的时候,这种空请求形成的伤害不容忽略。
浏览器如此实现也是根据RFC 3986 - Uniform Resource Identifiers标准,空的src被定义为当前页面。
因此注意咱们的网页中是否存在这样的代码
straight HTML
<img src="">
JavaScript
var img = new Image();
img.src = "";
Cookie
减小Cookie大小
Cookie被用来作认证或个性化设置,其信息被包含在http报文头中,对于cookie咱们要注意如下几点,来提升请求的响应速度,
去除没有必要的cookie,若是网页不须要cookie就彻底禁掉
将cookie的大小减到最小
注意cookie设置的domain级别,没有必要状况下不要影响到sub-domain
设置合适的过时时间,比较长的过时时间能够提升响应速度。
关于asp.net中的cookie能够参考ASP.NET Cookies Overview和Configure Use Cookies Mode for Session State (IIS 7)
页面内容使用无cookie域名
大多数网站的静态资源都不必cookie,咱们能够采用不一样的domain来单独存放这些静态文件,这样作不只能够减小cookie大小从而提升响应速度,还有一个好处是有些proxy拒绝缓存带有cookie的内容,若是能将这些静态资源cookie去除,那就能够获得这些proxy的缓存支持。
常见的划分domain的方式是将静态文件放在static.example.com,动态内容放在www.example.com。
也有一些网站须要在二级域名上应用cookie,全部的子域都会继承,这种状况下通常会再购买一个专门的域名来存放cookie-free的静态资源。例如Yahoo!的yimg.com,YouTube的ytimg.com等。
CSS
将样式表置顶
经样式表(css)放在网页的HEAD中会让网页显得加载速度更快,由于这样作可使浏览器逐步加载已将下载的网页内容。这对内容比较多的网页尤为重要,用户不用一直等待在一个白屏上,而是能够先看已经下载的内容。
若是将样式表放在底部,浏览器会拒绝渲染已经下载的网页,由于大多数浏览器在实现时都努力避免重绘,样式表中的内容是绘制网页的关键信息,没有下载下来以前只好对不起观众了。
避免CSS表达式
CSS表达式能够动态的设置CSS属性,在IE5-IE8中支持,其余浏览器中表达式会被忽略。例以下面表达式在不一样时间设置不一样的背景颜色。
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
CSS表达式的问题在于它被从新计算的次数远比咱们想象的要多,不只在网页绘制或大小改变时计算,即便咱们滚动屏幕或者移动鼠标的时候也在计算,所以咱们仍是尽可能避免使用它来防止使用不当而形成的性能损耗。
若是想达到相似的效果咱们能够经过简单的脚本作到。
<html>
<head>
</head>
<body>
<script type="text/javascript">
var currentTime = new Date().getHours();
if (currentTime%2) {
if (document.body) {
document.body.style.background = "#B8D4FF";
}
}
else {
if (document.body) {
document.body.style.background = "#F08A00";
}
}
</script>
</body>
</html>
用<link>代替@import
避免使用@import的缘由很简单,由于它至关于将css放在网页内容底部。
避免使用Filters
AlphaImageLoad也是IE5.5 - IE8中支持,这种滤镜的使用会致使图片在下载的时候阻塞网页绘制,另外使用这种滤镜会致使内存使用量的问题。IE9中已经再也不支持。
Javascript
将脚本置底
HTTP/1.1 specification建议浏览器对同一个hostname不要超过两个并行下载链接, 因此当你从多个domain下载图片的时候能够提升并行下载链接数量。可是当脚本在下载的时候,即便是来自不一样的hostname浏览器也不会下载其余资源,由于浏览器要在脚本下载以后依次解析和执行。
所以对于脚本提速,咱们能够考虑如下方式,
把脚本置底,这样可让网页渲染所须要的内容尽快加载显示给用户。
如今主流浏览器都支持defer关键字,能够指定脚本在文档加载后执行。
HTML5中新加了async关键字,可让脚本异步执行。
使用外部Javascirpt和CSS文件
使用外部Javascript和CSS文件可使这些文件被浏览器缓存,从而在不一样的请求内容之间重用。
同时将Javascript和CSS从inline变为external也减少了网页内容的大小。
使用外部Javascript和CSS文件的决定因素在于这些外部文件的重用率,若是用户在浏览咱们的页面时会访问屡次相同页面或者能够重用脚本的不一样页面,那么外部文件形式能够为你带来很大的好处。但对于用户一般只会访问一次的页面,例如microsoft.com首页,那inline的javascript和css相对来讲能够提供更高的效率。
精简Javascript和CSS
精简就是将Javascript或CSS中的空格和注释全去掉,
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
精简后版本
body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}
统计代表精简后的文件大小平均减小了21%,即便在应用Gzip的文件也会减小5%。
例如个人网站上有5个CSS,4个Javascirpt,下面是分别通过bundling和minify以后的结果。
没有任何处理以前捆绑Javascript和CSS以后精简Javascript和CSS以后
用来帮助咱们作精简的工具不少,主要能够参考以下,
JS compressors:
Packer
JSMin
Closure compiler
YUICompressor (also does CSS)
AjaxMin (also does CSS)
CSS compressors:
CSSTidy
Minify
YUICompressor (also does JS)
AjaxMin (also does JS)
CSSCompressor
与VS集成比较好的工具以下.
YUICompressor - 编译集成,包含在NuGet.
AjaxMin - 编译集成
去除重复脚本
重复的脚本不只浪费浏览器的下载时间,并且浪费解析和执行时间。通常用来避免引入重复脚本的作法是使用统一的脚本管理模块,这样不只能够避免重复脚本引入,还能够兼顾脚本依赖管理和版本管理。
减小DOM访问
经过Javascript访问DOM元素没有咱们想象中快,元素多的网页尤为慢,对于Javascript对DOM的访问咱们要注意
缓存已经访问过的元素
Offline更新节点而后再加回DOM Tree
避免经过Javascript修复layout
使用智能事件处理
这里说智能的事件处理须要开发者对事件处理有更深刻的了解,经过不一样的方式尽可能少去触发事件,若是必要就尽早的去处理事件。
好比一个div中10个按钮都须要事件句柄,那么咱们能够将事件放在div上,在事件冒泡过程当中捕获该事件而后判断事件来源。
图片
优化图像
当美工完成了网站的图片设计后,咱们能够在上传图片以前对其作如下优化
检查GIF图片中图像颜色的数量是否和调色板规格一致。若是你发现图片中只用到了4种颜色,而在调色板的中显示的256色的颜色槽,那么这张图片就还有压缩的空间。可使用imagemagick检查:
identify -verbose image.gif
尝试把GIF格式转换成PNG格式,看看是否节省空间。大多数状况下是能够压缩的。下面这条简单的命令能够安全地把GIF格式转换为PNG格式:
convert image.gif image.png
在全部的PNG图片上运行pngcrush(或者其它PNG优化工具)。例如:
pngcrush image.png -rem alla -reduce -brute result.png
在全部的JPEG图片上运行jpegtran。这个工具能够对图片中的出现的锯齿等作无损操做,同时它还能够用于优化和清除图片中的注释以及其它无用信息
jpegtran -copy none -optimize -perfect src.jpg dest.jpg
优化CSS Sprite
Spirite中水平排列图片,垂直排列会增长文件大小;
Spirite中把颜色较近的组合在一块儿能够下降颜色数,理想情况是低于256色以便适用PNG8格式;
不要在Spirite的图像中间留有较大空隙。这虽然不大会增长文件大小,但对于用户代理来讲它须要更少的内存来把图片解压为像素地图。100×100的图片为1万像素,1000×1000就是100万像素。
不要在HTML中缩放图片
不要经过图片缩放来适应页面,若是你须要小图片,就直接使用小图片吧。
使用小且可缓存的favicon.ico
网站图标文件favicon.ico,无论你服务器有仍是没有,浏览器都会去尝试请求这个图标。因此咱们要确保这个图标
存在
文件尽可能小,最好小于1k
设置一个长的过时时间
移动客户端
保持单个内容小于25KB
这限制是由于iphone,他只能缓存小于25K,注意这是解压后的大小。因此单纯gzip不必定够用,精简文件工具要用上了。
打包组建成符合文档
把页面内容打包成复合文本就如同带有多附件的Email,它可以使你在一个HTTP请求中取得多个组建。当你使用这条规则时,首先要确