《高性能网站建设指南》学习笔记

在线示例:
http://stevesouders.com/hpws
序言A  前端性能的重要性
性能黄金法则:
只有10%~20%的最终用户响应时间花在了下载HTML文档上,其余的80%~90%时间花在了下载页面中的所有组件上。

序言B  HTTP概述
请求类型有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE。
GET请求包含一个URL,当然是头。
HTTP响应包含状态码、头、响应体。

压缩
如果浏览器和服务器都支持的话,可以使用压缩来减小响应的大小。
--->    GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js
    HTTP 1.1
    Host: us.js2.yimg.com
    User-Agent: Mozilla/5.0(...) Gecko/20061206 Firefox/1.5.0.9
    Accept-Encoding: gzip, deflate // 浏览器使用Accept-Encoding头来声明它支持的压缩。

<---    HTTP 1.1 200 OK
    Content-Type: application/x-javascript
    Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT
    Content-Length: 255
    Content-Encoding: gzip // 服务器用Content-Encoding头确认响应已被压缩。

    ^_\213^H^@^@^@^@^@^@^C1\217\315j\3030^P\204_E\316IJ...

条件GET请求
如果浏览器在其缓存中保留了组件的一个副本,但并不确定它是否仍然有效,就会生成一个条件GET请求。
--->    GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js
    HTTP 1.1
    Host: us.js2.yimg.com
    User-Agent: Mozilla/5.0(...) Gecko/20061206 Firefox/1.5.0.9
    Accept-Encoding: gzip, deflate
    If-Modified-Since: Wed, 22 Feb 2006 04:15:54 GMT // 浏览器在说:“我拥有这个组件的一个版本,这是它的组后修改时间,我可以使用它吗?”。

<---    HTTP 1.1 304 Not Modified
    Content-Type: application/x-javascript
    Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT  // 如果组件自生成日期以来没有改变过,服务器会返回一个“304 Not Modified”状态码并不再发送响应体。

Expires
条件GET请求仍需要在客户端和服务器之间进行一次往返确认。Expires头通过明确指出浏览器是否可以组件的缓存副本来消除这个需要。
<---    HTTP 1.1 200 OK
    Content-Type: application/x-javascript
    Last-Modifide: Wed, 22 Feb 2006 04:15:54 GMT
    Expires: Wed, 05 Oct 2016 19:16:20 GMT // 当浏览器看到Expires头时,它会把相应的过期时间和组件一起保存到其缓存中,只要组件没有过期,浏览器就会使用缓存版本而不会进行任何HTTP请求。

Keep-Alive
--->    GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js
    HTTP 1.1
    Host: us.js2.yimg.com
    User-Agent: Mozilla/5.0(...) Gecko/20061206 Firefox/1.5.0.9
    Accept-Encoding: gzip, deflate
    Connection: keep-alive // keep-alive使浏览器可以在一个单独的连接上进行多个请求

<---    HTTP 1.1 200 OK
    Content-Type: application/x-javascript
    Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT
    Connection: keep-alive  // 同上,浏览器或服务器可以通过发送一个Connection: close头来关闭连接

规则1  减少HTTP请求

图片地图:
将多张图片合并为一张图片,从而减少HTTP请求
服务器图片地图:将所有点击提交到同一个目标URL,向其传递用户单击的x、y坐标,Web应用程序将该x、y坐标映射为适当的操作。
客户端图片地图:将用户的点击映射到一个操作,无需向后端应用程序发送请求
<img usemap="#map1" border=0 src="/images/imagemap.gif?t=1196816255">
<map name="map1">
    <area shape="rect" coords="0,0,31,31" href="home.html" title="Home"> // coords为area左上角坐标和右下角坐标
    <area shape="rect" coords="36,0,66,31" href="gifts.html" title="Gifts">
    <area shape="rect" corrds="71,0,101,31" href="cart.html" title="Cart">
    <area shape="rect" corrds="141,0,171,31" href="help.html" title="Help">
</map>

CSS Sprites(CSS 精灵)
CSS Sprites也可以合并图片,但更为灵活,且图片地图中的图片必须是连续的,而CSS Sprites则没有这个限制。
<style>
#navbar span {
    width:31px;
    height:31px;
    display:inline;
    float:left;
    background-image:url(/images/spritebg.gif); // div的背景图片,即将多个图合并为一个后的图
}
.home        {background-position:0 0; margin-right:4px; margin-left:4px;}
.gifts        {background-position:-32px 0; margin-right:4px;}
.cart        {background-position:-64px 0; margin-right:4px;}
.settings    {background-position:-96px 0; margin-right:4px;}
.help        {background-position:-128px 0; margin-right:0px;}

<div id="navbar" style="background-color: #F4F5EB; border: 2px ridge #333; width: 180px; height: 32px; padding: 4px 0 4px 0;">
    <a href="javascript:alert('Home')" title="Home"><span class="home"></span></a> // 连接被包围在一个SPAN中
    <a href="javascript:alert('Gifts')" title="Gifts"><span class="gifts"></span></a> // 连接被包围在一个SPAN中
    <a href="javascript:alert('Cart')" title="Cart"><span class="cart"></span></a> // 连接被包围在一个SPAN中
    <a href="javascript:alert('Settings')" title="Settings"><span class="settings"></span></a> // 连接被包围在一个SPAN中
    <a href="javascript:alert('Help')" title="Help"><span class="help"></span></a> // 连接被包围在一个SPAN中
</div>
CSS Sprites能通过合并图片减少HTTP请求,且比图片地图更灵活,而且还能降低下载量。因为合并后的图片比分离的图片的总和要小,因为它降低了图片自身的开销。

内联图片
通过使用data:URL模式可以在Web页面中包含图片但无需任何额外的HTTP请求。
在下面示例中,外部样式表的URL指向一个PHP模板---http://stevesouders.com/hpws/inline-css-images-css.php,PHP函数file_get_contents可以很容易地通过从磁盘中读取图片并将其内容插入到页面中来创建内联图片。
.home {background-image: url(data:image/gif;base64,<?php echo base64_encode(file_get_contents("../images/home.gif"))?>);}
.gift {background-image: url(data:image/gif;base64,<?php echo base64_encode(file_get_contents("../images/gift.gif"))?>);}
.cart {background-image: url(data:image/gif;base64,<?php echo base64_encode(file_get_contents("../images/cart.gif"))?>);}
.settings {background-image: url(data:image/gif;base64,<?php echo base64_encode(file_get_contents("../images/settings.gif"))?>);}
.help {background-image: url(data:image/gif;base64,<?php echo base64_encode(file_get_contents("../images/help.gif"))?>);}

合并脚本和样式表
将多个脚本和样式表合并到一个脚本和样式表中,可以减少HTTP请求的数量并缩短用户响应时间。理想情况,一个页面应该使用一个脚本和样式表。

###减少HTTP请求###

规则2  使用内容发布网络
内容发布网络(CDN)是一组分布在多个不同地理位置的Web服务器,用于更加有效地向用户发布内容。CDN用于发布静态内容。无论如何不要使用HTTP重定向来将用户指向本地服务器,这会使Web页面反应速度变慢。

###使用内容发布网络CDN###

规则3  添加Expires头
Expires头
Expires: Thu, 15 Apr 2010 20:00:00 GMT // 在这一日期/时间之后,响应将被认为是无效的

Max-Age
HTTP 1.1 中Cache-Control使用max-age指令指定组件被缓存多久,它以秒为单位定义了一个更新窗。
<---    Cache-Control: max-age=315360000 // 将刷新窗设置为未来10年

不仅仅是图片
长久的Expires头应该包含任何不经常变化的组件,包括脚本、样式表、图片

修订文件名
为了确保用户能获得组件的最新版本,需要在所有HTML页面中修改组件的文件名。Mark Nottingham称:“最有效的解决方案是修改其所有链接,这样,全新的请求将从原始服务器下载最新的内容。
使用PHP等动态语言生成HTML页,只需修改变量,就能将版本号嵌在组件的文件名中,而且在全局映射中修订过的文件名会自动更新,调试时也很容易找到准确的源代码。

大部分图片、样式表、脚本都可缓存30天以上。

###为组件添加长久的Expires头###

规则4  压缩组件
压缩是如何工作的
--->    Accept-Encoding: gzip, deflate // HTTP 1.1 中,Web客户端可以通过HTTP请求中的Accept-Encoding头来标识对压缩的支持。
<---    Content-Encoding: gzip // Web服务器通过响应中的Content-Encoding头来通知Web客户端。

压缩什么
可以对HTML文档、脚本、样式表,以及XML和JSON在内的任何文本响应。图片和PDF不因该压缩,因为它们本来就已经被压缩了。
根据经验通常对大于1KB或2KB的文件进行压缩,mod_gzip_minimum_file_size指令控制着希望压缩文件的最小值,默认值是500B。

节省
压缩通常能将响应的数据量减少将近70%。

代理缓存
代理缓存问题:发送给代理请求的浏览器可能支持也可能不支持压缩,就有可能把压缩文件发送给不支持压缩的浏览器
解决这一问题的方法是在Web服务器的响应头中添加Vary头,Vary头中包含Accept-Encoding
<---    Vary: Accept-Encoding

边缘情形
添加浏览器白名单

###压缩脚本和样式表###

规则5  将样式表放在顶部
逐步呈现
将样式表放在文档顶部的HEAD中,页面将是逐步呈现的。

将CSS放在顶部
将样式表包含在文档中有两种方式:使用LIN标签和@import规则。
<link rel="stylesheet" href="styles1.css">
<style>
    @import url("styles2.css");
</style> // @import规则必须放在其他规则之前,且使用@import规则会导致组件下载的无序性,可能会产生白屏。

###使用LINK标签将样式表放在文档HEAD中###

规则5  将样式表放在顶部

<link rel="stylesheet" href="styles1.css"> // @import规则会导致组件下载时的无序性,可能会导致白屏现象,link语法简单且性能更好

###使用LINK标签将样式表放在文档HEAD中###

规则6  将脚本放在底部
脚本会阻塞并行下载,会阻止页面内容的呈现,导致白屏现象,因而放置脚本最好的地方是页面的底部。

###将脚本移到页面的底部###

规则7  避免CSS表达式
表达式不只是在页面呈现和大小改变时求值,当页面滚动、甚至用户鼠标在页面上移过时都要求值。在页面上来回移动鼠标可以很轻松地产生10000次以上的求值。

###避免CSS表达式###

规则8  使用外部JavaScript和CSS
纯粹而言,内联快一些,但外部JavaScript和CSS文件可以被浏览器缓存起来。

加载后下载:既可以获得内联优势,又能缓存外部文件
<script>
    function doOnload() {
        setTimeout("downloadComponents()", 1000); // 延迟1妙保证页面呈现完毕
    }
    
    window.onload = doOnload; // onload事件

    function downloadComponents() {
        downloadJS("http://stevesouders.com/examples/testsma.js");
        downloadCSS("http://stevesouders.com/examples/testsma.css");
    }

    function downloadJS(url) {
        var elem = document.createElement("script");
        elem.src = url;
        document.body.appendChild(elem);
    }

    function downloadCSS(url) {
        var elem = document.createElement("link");
        elem.rel = "stylesheet";
        elem.type = "text/css";
        elem.href = url;
        document.body.appendChild(elem);
    }
</script>

动态内联:可以在内联或使用外部文件之间作出最佳选择。如果cookie不存在,就内联JavaScript和CSS,且加载后下载外部文件,如果cookie出现,则可能外部组件位于浏览器的缓存中,就使用外部文件。

###将JavaScript和CSS放到外部文件中###

规则9  减少DNS查找
减少唯一主机名可以减少DNS查找,但会减少页面并行下载的数量。建议使用2-4个主机名。

###通过使用Keep-Alive和较少的域名来减少DNS查找###

规则10  精简JavaScript
精简:移除注释、空格、换行、制表符。
精简JavaScript代码的工具有JSMin(http://crockford.com/javascript/jsmin)和ShrinkSafe(http://dojotoolkit.org/docs/shrinksafe)
JSMin可以使JavaScript文件的大小减小21%,ShrinkSafe可以达到25%。

###对JavaScript源代码进行精简###

规则11  避免重定向
重定向会延迟整个HTML文档的传输,在HTML文档到达之前,页面不会呈现任何东西。

缺少结尾的斜线
在请求http://astrology.yahoo.com/astrology时会导致一个301响应,其中包含了一个到http://astrology.yahoo.com/astrology/的重定向,唯一的区别就是在结尾添加了斜线。这种重定向最为浪费、发生的也很频繁。

跟踪内部流量
可以使用Referer日志来跟踪流量去向,使用Referer日志可以避免重定向。

跟踪出站流量
可以使用信标来跟踪出站流量,信标响应通常是一个1px * 1px的透明图片,不过204响应更为优秀。

###寻找一种避免重定向的方法###

规则12  移除重复脚本
可以在模板系统中实现一个脚本管理模块来避免重复脚本。

###确保脚本只被包含一次###

规则13  配置ETag
实体标签(Entity Tag, ETag)
--->    GET /i/yahoo.gif HTTP 1.1
    Host: us.yimg.com

<---    HTTP 1.1 200 OK
    Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
    ETag: "10c24bc-4ab-457e1c1f"
    Content-Length: 1195
ETag的问题在于,ETag对于服务器来说是唯一的,当浏览器从一台服务器上获取了原始组件,之后又向另外一台服务器发送GET请求时,ETag不会匹配。对于拥有多台服务器的网站,ETag会大大降低有效性验证的成功率。

###配置或移除ETag###

规则14  使Ajax可缓存
XMLHttpRequest是Ajax的核心。

###确保Ajax请求遵守性能指导,尤其应具有长久的Expires头。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值