后续补思维导图和引申内容!
1. 性能黄金法则:
只有10% - 20%的最终用户响应时间花在了下载HTML文档商,其余80% - 90%时间花在了下载页面的所有组件上。
2. 前端优化定义
是指从用户输入URL到页面完成渲染呈现的整个过程中提升网页的性能。
3. 用户输入URL后发生了什么?
1) 浏览器的地址栏输入URL并按下回车
(引申:HTTP协议-HTTP1.0 1.1 2.0、HTTPs、FTP协议)
(引申:同源策略和跨域问题)(引申:XSS攻击和CSRF攻击)
(引申:默认端口 80 443)
2) 找缓存:
浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
查找顺序:浏览器缓存和本地缓存=》DNS缓存=》找不到则进行下一步DNS解析。
(引申:强制缓存(Cache-Control、Expires)和协商缓存(last-modified、Etag))
3) DNS域名解析URL对应的IP地址
(引申:域名还原为IP地址的过程)
4) 根据IP建立TCP连接
(引申:三次握手)
5)HTTP发送请求
(引申:HTTP请求报文)
6)服务器处理请求,浏览器接收HTTP响应
(引申:HTTP的Request对象三部分(状态码,响应头,响应报文))
7) 浏览器解析响应报文,构建DOM树并渲染页面。
(引申:页面渲染-解析和渲染、layout重排/回流和repaint重绘、JS阻塞、CSS阻塞)
8) 关闭TCP连接
(引申:四次挥手)
4. 优化方法分类
Yahoo的《Best Practices for Speeding Up Your Web Site》将优化方法分成了7类,分别从网页内容、服务器、cookie、CSS、JavaScript、图片和移动端进行了处理。
网页内容 | 服务器 | CSS | JavaScript |
---|---|---|---|
减少HTTP请求次数 | 使用CDN | 将样式表置顶 | 将脚本置底 |
减少DNS查询次数 | 添加Expires或cache-control报文头 | 避免CSS表达式 | 使用外部JavaScript和CSS文件 |
避免页面跳转/重定向 | Gzip压缩传输文件 | 用link代替@import | 缩小JavaScript和CSS |
缓存Ajax | 配置ETags实体标记 | 避免使用Filters | 去除重复脚本 |
延迟加载 | 尽早flush输出 | 减少DOM访问 | |
提前加载 | 使用GET Ajax请求 | 图片 | 使用智能事件处理 |
减少DOM元素数量 | 避免空的图片src | 优化图像 | |
根据域名划分内容 | Cookie | 优化CSS Sprite | 移动客户端 |
减少iframe数量 | 减少cookie大小 | 不要在HTML中缩放图片 | 保持单个内容小于25KB |
避免404 | 对组件使用无cookie域 | 使用小且可以缓存的favicon.ico | 打包组建成复合文档 |
1) 网页内容(10种)
a) 减少HTTP请求次数
(合并文件-所有脚本组合到一个脚本中、CSS精灵图-将背景图像组合成单个图像、图片地图-将多个(连续的)图像组合成一个图像、内联图像-将内联图像合并到缓存的样式表)
b) 减少DNS查询次数
(当客户端的DNS缓存为空时,DNS查找的次数等于web页面中唯一主机名的数量。这包括页面URL中使用的主机名、图像、脚本文件、样式表、Flash对象等。
减少唯一主机名的数量可以减少DNS查找的次数,也有可能减少页面中发生的并行下载的数量。避免DNS查找会缩短响应时间,但减少并行下载可能会增加响应时间。
指导方针是将这些组件拆分到至少两个但不超过四个主机名上。这在减少DNS查找和允许高度并行下载之间得到了很好的折中。)
c) 避免页面跳转/重定向
(301 302状态码, URL末尾不加/会导致重定向, 重定向会延迟页面中的所有内容,因为在页面中没有东西可以呈现,并且没有组件可以开始下载,直到HTML文档到达。)
d) 缓存Ajax
(异步不等于瞬时,提高Ajax性能的最重要方法是使响应可缓存,如添加Expires或Cache-Control头中讨论的那样。其他一些规则也适用于Ajax: Gzip组件,减少DNS查找,缩小JavaScript,避免重定向,配置ETags。)
e) 延迟加载
(在确保页面正常工作之后,可以使用一些post-loaded延迟加载脚本来增强它,这些脚本可以提供更多的附加功能,比如拖放和动画。)
f) 提前加载
(可以利用浏览器空闲的时间,并请求将来需要的组件(如图像、样式和脚本),类型有:无条件预加载- onload触发,条件预加载-有根据的猜测进行预加载,预期加载-在启动重新设计之前预加载一些组件)
g) 减少DOM元素数量
(一个复杂的页面意味着需要下载更多字节,同时也意味着用JavaScript访问DOM会更慢,请在有在语义上有意义时才使用
h) 根据域名划分内容
(拆分组件可以让你最大化并行下载。请确保您使用的域名不超过2-4个,因为DNS查找存在惩罚。)
i) 减少iframe数量
(Iframes允许将HTML文档插入到父文档中,iframe优点-缓慢第三方内容/安全沙箱/并行下载脚本,iframe缺点-即使空白花费也很大/Block Page加载/无语义)
j) 避免404
(HTTP请求是昂贵的,更糟糕的是当JS的链接错误,这个下载将阻止并行下载,浏览器可能会尝试解析404响应体,试图挖掘有用东西)
2)服务器(7种)
a) 使用CDN
(分散静态内容,为用户选择网络跳数最少的服务器或响应时间最快的服务器)
b) 添加Expires或cache-control报文头
(浏览器(和代理)使用缓存来减少HTTP请求的数量和大小,使网页加载更快)
c) Gzip压缩传输文件
(压缩通过减少HTTP响应的大小来减少响应时间。从HTTP/1.1开始,web客户端通过HTTP请求中的Accept-Encoding头来表示对压缩的支持。压缩任何文本响应,如 HTML文档 脚本 样式表 XML JSON等,图片PDF不值得压缩)
d) 配置ETags实体标记
(是web服务器和浏览器用来确定浏览器缓存中的组件是否与源服务器上的组件匹配的一种机制。源服务器使用ETag响应头指定组件的ETag。如果ETags匹配,则返回304状态码)
e) 尽早flush输出
(网页后台程序中有个方法叫Response.Flush(),尽早冲刷服务器缓存,目的是将现有缓存中的回复先发给客户端,让客户端“有活干”。)
f) 使用GET Ajax请求
(当使用XMLHttpRequest时,POST在浏览器中实现为两步过程:首先发送头部,然后发送数据。因此,最好使用GET,它只需要发送一个TCP包,注意:发送超过2K的数据可能无法使用GET)
g) 避免空的图片src
(空的图像地址都会使浏览器向服务器发出另一个请求。会导致:①发送大量意想不到的流量会使服务器瘫痪;②浪费服务器计算周期,生成一个永远不会被查看的页面;③可能破坏用户数据-浏览器也会读取请求并接受所有的头,包括所有的cookie。)
3)Cookie(2种)
a) 减少cookie大小
(关于cookie的信息会在web服务器和浏览器之间通过HTTP头进行交换。减少cookie大小,可以降低对用户响应时间的影响。方法:消除不必要的cookie;降低cookie大小;在适当的域级别设置cookie;适当设置有效期)
b) 对组件使用无cookie域
(使用无cookie请求请求静态组件。创建一个子域并在那里托管所有静态组件。如果你的域名是www.example.org,你可以在static.example.org上托管你的静态组件。在无cookie域上托管静态组件的另一个好处是,一些代理可能会拒绝缓存使用cookie请求的组件。)
4)CSS(4种)
a) 将样式表置顶
(CSS放在底部禁止在IE等浏览器中渐进式呈现,当样式发生改变时会出现重绘)
b) 避免CSS表达式
(表达式的计算频率比大多数人预期的要高-页面呈现/调整大小/页面滚动均会触发,减少方法:使用一次性表达式,计算完就替换成固定值)
c) 用link代替@import
(在IE中@import的行为和在页面底部使用是一样的,所以最好不要使用它。)
d) 避免使用Filters
(IE专有的AlphaImageLoader过滤器旨在解决当IE版本小于7时的真彩png半透明效果,但这个过滤器的问题是当图片被下载时,它会阻塞呈现并冻结浏览器。它还增加了内存消耗,并且是每个元素应用,而不是每个图像,所以问题是成倍的。 最好的方法是:完全避免AlphaImageLoader,而使用优雅地降级的PNG8,这在IE中是很好的。如果你绝对需要AlphaImageLoader,使用下划线黑客_filter,以不惩罚你的IE7+用户。)
5)JavaScript(6种)
a) 将脚本置底
(脚本阻止并行下载,会导致JS阻塞,可以使用延迟脚本defer或者直接脚本置底)
b) 使用外部JavaScript和CSS文件
(内联JS和CSS文档减少了请求数量但是会增加HTML文档大小,重用的脚本和样式表,缓存的外部文件更适合)
c) 缩小JavaScript和CSS
(从代码中删除不必要的字符-注释/不需要的空白字符-以减少其大小,从而改善加载时间的做法)
d) 去除重复脚本
(重复脚本会创建不必要的HTTP请求和浪费的JavaScript执行,从而损害性能)
e) 减少DOM访问
(因为用JavaScript访问DOM元素比较慢,所以需要减少。应该:缓存访问元素的引用;“脱机”更新节点,然后将它们添加到树中;避免使用JavaScript修复布局)
f) 使用智能事件处理
(事件委托–如果在一个div中有10个按钮,则只向div包装器附加一个事件处理程序,而不是为每个按钮附加一个处理程序。事件会冒出来,因此您将能够捕捉事件并找出它来自哪个按钮。您也不需要等待onload事件来开始对DOM树做一些事情。)
6)图片(4种)
a) 优化图像
(将图片FTP到服务器之前可进行优化:①gif文件,看看它们是否使用了与图像中颜色数量对应的调色板大小;②尝试将gif转换为png,看看是否有一个保存。③在所有PNG上运行PNG优化工具;④在你所有的jpeg文件上做无损JPEG操作)
b) 优化CSS Sprite
(①在精灵中水平排列图像通常会导致较小的文件大小,而不是垂直排列。②结合类似的颜色在一个精灵帮助你保持颜色计数低,理想情况下低于256颜色,以便适合在一个PNG8。③“移动友好”,不要在精灵的图像之间留下大的间隔。这不会对文件大小产生太大影响,但用户代理将图像解压缩为像素映射所需的内存更少。)
c) 不要在HTML中缩放图片
(不要因为可以在HTML中设置宽度和高度,就使用比你需要的更大的图像。如果你需要一个100100px图像,那么你的图像(mycat.jpg)应该是100x100px,而不是按比例缩小的500500px图像。)
d) 使用小且可以缓存的favicon.ico
(ico是一个保存在服务器根目录中的图像。因为即使你不关心它,浏览器仍然会请求它,并且会干扰下载顺序,请确保:大小小于1K,设置舒服的Expires标题(因为不能重命名)。你可能可以安全地设置过期标题几个月后的未来。您可以查看当前favicon.ico的最后修改日期,以便作出明智的决定。)
7) 移动客户端(2种)
a) 保持单个内容小于25KB
(这个限制与iPhone不会缓存大于25K的组件有关。注意,这是未压缩的大小。这是缩小是重要的,因为仅gzip可能是不够的。)
b) 打包组建成复合文档
(将组件打包到一个包含多个部分的文档中就像一封带有附件的电子邮件,它可以帮助您通过一个HTTP请求获取多个组件,注意iphone不支持)