前端性能优化学习-1
前些时间主要学习了前端的性能优化的基础知识,总结笔记,准备进阶!
学习总结-1
几个关键的数据
- 白屏时间:用户从打开页面开始到页面开始有东西呈现为止,这过程中占用的时间就是白屏时间
- 首屏时间:用户浏览器首屏内所有内容都呈现出来所花费的时间
- 用户可操作时间:用户可以进行正常的点击、输入等操作。也就是domready的时间
- 页面总下载时间:页面所有资源都加载完成并呈现出来所花的时间,即页面 onload 的时间
如何收集页面加载过程中的信息
Ø 利用js打印不同时间点的时间戳
² 白屏时间:在head头部和底部分别嵌入脚本可以获得head头部的加载时间,这个时间过后页面开始程序内容,可以大致认为是白屏时间
² 用户可操作时间:默认可以统计domready时间,因为通常会在这时候绑定事件操作
² 页面总下载时间:可以统计onload时间
² 首屏时间:这个较为复杂,统计首屏所有内容呈现出来的时间,主要因素是图片的加载,异步渲染,iframe等
Ø 利用高版本浏览器api获得数据
window.performance的navigation和timing接口提供了丰富的信息
² navigation提供的信息:用户访问页面的形式和关于访问重定向的一些相关信息
ü timing提供的信息:文档解析各个步骤的耗时
ü .navigationStart 准备加载页面的起始时间
ü .unloadEventStart 如果前一个文档和当前文档同源,返回前一个文档开始unload的时间
ü .unloadEventEnd 如果前一个文档和当前文档同源,返回前一个文档开始unload结束的时间
ü .redirectStart 如果有重定向,这里是重定向开始的时间.
ü .redirectEnd 如果有重定向,这里是重定向结束的时间.
ü .fetchStart 开始检查缓存或开始获取资源的时间
ü .domainLookupStart 开始进行dns查询的时间
ü .domainLookupEnd dns查询结束的时间
ü .connectStart 开始建立连接请求资源的时间
ü .connectEnd 建立连接成功的时间.
ü .secureConnectionStart 如果是https请求.返回ssl握手的时间
ü .requestStart 开始请求文档时间(包括从服务器,本地缓存请求)
ü .responseStart 接收到第一个字节的时间
ü .responseEnd 接收到最后一个字节的时间.
ü .domLoading ‘current document readiness’ 设置为 loading的时间 (这个时候还木有开始解析文档)
ü .domInteractive 文档解析结束的时间
ü .domContentLoadedEventStart DOMContentLoaded事件开始的时间
ü .domContentLoadedEventEnd DOMContentLoaded事件结束的时间
ü .domComplete current document readiness被设置 complete的时间
ü .loadEventStart 触发onload事件的时间
ü .loadEventEnd onload事件结束的时间
一些分析性能的工具
- Webpagetest http://www.webpagetest.org/
- pagespeed https://developers.google.com/speed/pagespeed/ 基于webpagetest并提供优化建议
- webspeed http://dp.baidu.com/ 百度fex的分析系统
- jsperf http://jsperf.com/ 测试js的性能的工具
- http://phantomjs.org/
http://yslow.org/ 提供相应的chrome插件,并遵从yahu的优化法则提供优化的建议。
以上是一些业界做的比较好的工具,主要是对页面的白屏时间,首屏时间等指标,页面重绘次数,dom数,页面大小,总下载时间等。
Pagespeed和yslow都根据雅虎的优化法则提供一些优化的建议。
一些优化法则(贴吧大部分都已实现优化)
1、 尽量减少HTTP请求次数
http比较耗时,应尽可能减少请求。
- 合并文件:合并css 合并js
- Css sprite:减少图像请求的有效方法
- 内联图像:使用data:URL scheme的方法把图像数据加载页面中
贴吧实践:combo js/css ,css sprit
2、减少DNS查找次数
减少主机名的数量也会减少页面中并行下载的数量。减少DNS查找次数可以节省响应时间,但是减少并行下载却会增加响应时间。指导原则是把这些页面中的内容分割成至少两部分但不超过四部分。这种结果就是在减少DNS查找次数和保持较高程度并行下载两者之间的权衡了。
贴吧实践:静态文件不再不同的域下的静态服务器。
3、 避免跳转
当URL本该有斜杠(/)却被忽略掉时。例如,当我们要访问http://astrology.yahoo.com/astrology 时,实际上返回的是一个包含301代码的跳转,它指向的是http://astrology.yahoo.com/astrology/ (注意末尾的斜杠)。在Apache服务器中可以使用Alias 或者 mod_rewrite或者the DirectorySlash来避免
4、 可缓存的AJAX
5、 推迟加载内容
哪些内容是页面呈现时所必需首先加载的。
预加载是在浏览器空闲时请求将来可能会用到的页面内容(如图像、样式表和脚本)。使用这种方法,当用户要访问下一个页面时,页面中的内容大部分已经加载到缓存中了,因此可以大大改善访问速度。
贴吧实践:滚动加载,把内容数据存储在不可见元素里(textarea)
6、 减少DOM元素数量(减少页面体积)
贴吧实践:缩减页面体积,减少pageData的重量
7、 根据域名划分页面内容
由于DNS查找带来的影响你首先要确保你使用的域名数量在2个到4个之间。
贴吧实践:静态文件不再不同的域下的静态服务器。
8、 使iframe的数量最小
<iframe>优点:
解决加载缓慢的第三方内容如图标和广告等的加载问题
Security sandbox
并行加载脚本
<iframe>的缺点:即时内容为空,加载也需要时间
会阻止页面加载
没有语意
9、 不要出现404错误
10、
使用内容分发网络(Content Delivery
Network,CDN)
贴吧实践:cdn
11、 为文件头指定Expires或Cache-Control
这条守则包括两方面的内容:
对于静态内容:设置文件头过期时间Expires的值为“Never expire”(永不过期)
对于动态内容:使用恰当的Cache-Control文件头来帮助浏览器进行有条件的请求
贴吧实践:缓存静态文件
12、 Gzip压缩文件内容
服务器根据文件类型来选择需要进行gzip压缩的文件,但是这过于限制了可压缩的文件。大多数web服务器会压缩HTML文档。对脚本和样式表进行压缩同样也是值得做的事情,但是很多web服务器都没有这个功能。实际上,压缩任何一个文本类型的响应,包括XML和JSON,都值得的。图像和PDF文件由于已经压缩过了所以不能再进行gzip压缩。如果试图gizp压缩这些文件的话不但会浪费CPU资源还会增加文件的大小。
Gzip压缩所有可能的文件类型是减少文件体积增加用户体验的简单方法。
贴吧实践:开启gzip压缩
13、 配置ETag
14、
Entity tags(ETags)(实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制(“实体”就是所说的“内容”,包括图片、脚本、样式表等)。增加ETag为实体的验证提供了一个比使用“last-modified date(上次编辑时间)”更加灵活的机制。Etag是一个识别内容版本号的唯一字符串。唯一的格式限制就是它必须包含在双引号内
贴吧实践:配置etag缓存静态文件,方法同为文件头指定Expires或Cache-Control ,主要是触发浏览器的缓存
15、
尽早刷新输出缓冲
贴吧实践:东伟正在做的事情,bigpipe依赖的原理
16、 使用GET来完成AJAX请求
Yahoo!Mail团队发现,当使用XMLHttpRequest时,浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。因此使用GET最为恰当,因为它只需发送一个TCP包(除非你有很多cookie)
17、 把样式表置于顶部
在研究Yahoo!的性能表现时,我们发现把样式表放到文档的<head />内部似乎会加快页面的下载速度。这是因为把样式表放到<head />内会使页面有步骤的加载显示。
避免页面渲染过程中的闪烁
18、 避免使用CSS表达式(Expression)
表达式的问题就在于它的计算频率要比我们想象的多。不仅仅是在页面显示和缩放时,就是在页面滚动、乃至移动鼠标时都会要重新计算一次。给CSS表达式增加一个计数器可以跟踪表达式的计算频率。在页面中随便移动鼠标都可以轻松达到10000次以上的计算量
css表达式在渲染过程中特别耗性能,
19、 使用外部JavaScript和CSS
在实际应用中使用外部文件可以提高页面速度,因为JavaScript和CSS文件都能在浏览器中产生缓存。内置在HTML文档中的JavaScript和CSS则会在每次请求中随HTML文档重新下载。这虽然减少了HTTP请求的次数,却增加了HTML文档的大小。从另一方面来说,如果外部文件中的JavaScript和CSS被浏览器缓存,在没有增加HTTP请求次数的同时可以减少HTML文档的大小。
外置css ,js主要是缓存,主要考虑外置和内置的优缺点及二者之间的平衡
20、 削减JavaScript和CSS
精简是指从去除代码不必要的字符减少文件大小从而节省下载时间。消减代码时,所有的注释、不需要的空白字符(空格、换行、tab缩进)等都要去掉
代码压缩
21、用<link>代替@import
前面的最佳实现中提到CSS应该放置在顶端以利于有序加载呈现。
在IE中,页面底部@import和使用<link>作用是一样的,因此最好不要使用它。
@import 是页面加载之后才会引入css,会引起闪烁,关于link和import的区别还有别的方面
22、避免使用滤镜
IE独有属性AlphaImageLoader用于修正7.0以下版本中显示PNG图片的半透明效果。这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。在每一个元素(不仅仅是图片)它都会运算一次,增加了内存开支,因此它的问题是多方面的。
完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果你确实需要使用AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效
在ie中应避免使用滤镜,增加内存开支,耗性能
23、把脚本置于页面底部
脚本带来的问题就是它阻止了页面的平行下载。HTTP/1.1 规范建议,浏览器每个主机名的并行下载内容不超过两个。如果你的图片放在多个主机名上,你可以在每个并行下载中同时下载2个以上的文件。但是当下载脚本时,浏览器就不会同时下载其它文件了,即便是主机名不相同。
避免阻塞页面渲染和其他文件的并行加载
24、剔除重复脚本
一个避免偶尔发生的两次引用同一脚本的方法是在模板中使用脚本管理模块引用脚本。在HTML页面中使用<script
/>标签引用脚本的最常见方法就是:
<script
type="text/javascript"
src="menu_1.0.17.js"></script>
在PHP中可以通过创建名为insertScript的方法来替代:
<?php
insertScript("menu.js") ?>
为了防止多次重复引用脚本,这个方法中还应该使用其它机制来处理脚本,如检查所属目录和为脚本文件名中增加版本号以用于Expire文件头等。
贴吧采用html::script的方式引入脚本文件
25、减少DOM访问
使用JavaScript访问DOM元素比较慢,因此为了获得更多的应该页面,应该做到:
缓存已经访问过的有关元素
线下更新完节点之后再将它们添加到文档树中
避免使用JavaScript来修改页面布局
减少dom访问,缓存dom节点
26、开发智能事件处理程序
有时候我们会感觉到页面反应迟钝,这是因为DOM树元素中附加了过多的事件句柄并且些事件句病被频繁地触发。这就是为什么说使用event delegation(事件代理)是一种好方法了。
27、减小Cookie体积
HTTP coockie可以用于权限验证和个性化身份等多种用途。coockie内的有关信息是通过HTTP文件头来在web服务器和浏览器之间进行交流的。因此保持coockie尽可能的小以减少用户的响应时间十分重要。
有关更多信息可以查看Tenni Theurer和Patty Chi的文章“When the Cookie Crumbles”。这们研究中主要包括:
去除不必要的coockie
使coockie体积尽量小以减少对用户响应的影响
注意在适应级别的域名上设置coockie以便使子域名不受影响
设置合理的过期时间。较早地Expire时间和不要过早去清除coockie,都会改善用户的响应时间。
Cookie会每次在http中进行传输,静态文件放在不同于主域名的域名,tb1.bdstatic.com这个域下不会携带cookie,利用locatstorage
28、对于页面内容使用无coockie域名
当浏览器在请求中同时请求一张静态的图片和发送coockie时,服务器对于这些coockie不会做任何地使用。因此他们只是因为某些负面因素而创建的网络传输。所有你应该确定对于静态内容的请求是无coockie的请求。创建一个子域名并用他来存放所有静态内容。imgsrc.baidu.com域下的静态图片有cookie
Tb1,tb2.bdstatic.com/这个域下的静态请求是没有cookie的
30、优化CSS Spirite
在Spirite中水平排列你的图片,垂直排列会稍稍增加文件大小;
Spirite中把颜色较近的组合在一起可以降低颜色数,理想状况是低于256色以便适用PNG8格式;
便于移动,不要在Spirite的图像中间留有较大空隙。这虽然不大会增加文件大小但对于用户代理来说它需要更少的内存来把图片解压为像素地图。100x100的图片为1万像素,而1000x1000就是100万像素。
Spirite中水平排列你的图片,垂直排列会稍稍增加文件大小
31、不要在HTML中缩放图像
不要为了在HTML中设置长宽而使用比实际需要大的图片。如果你需要:
<img width="100"
height="100" src="mycat.jpg" alt="My Cat" />
那么你的图片(mycat.jpg)就应该是100x100像素而不是把一个500x500像素的图片缩小使用。
32、favicon.ico要小而且可缓存
33、保持单个内容小于25K
这条限制主要是因为iPhone不能缓存大于25K的文件。注意这里指的是解压缩后的大小。由于单纯gizp压缩可能达不要求,因此精简文件就显得十分重要。
34、打包组件成复合文本
针对上述优化法则中几个法则学习的技术点
为什么要外置css/js? Expire,cache-control和etag的区别是啥?浏览器怎样缓存?
浏览器的缓存机制
用户行为与缓存
浏览器缓存行为还有用户的行为有关!!!用户行为决定了浏览器是否启用缓存,是直接走缓存还是间接走缓存。
用户操作 |
Expires/Cache-Control |
Last-Modified/Etag |
地址栏回车 |
有效 |
有效 |
页面链接跳转 |
有效 |
有效 |
新开窗口 |
有效 |
有效 |
前进、后退 |
有效 |
有效 |
F5刷新 |
无效 |
有效 |
Ctrl+F5刷新 |
无效 |
无效 |
如果是初次无缓存浏览的话:
流程
浏览器请求 => 无缓存 è 发送请求向服务器 è 缓存协商 è 呈现
浏览器请求
è有缓存
è 缓存没有过期 è 直接读取浏览器缓存
è缓存过期,发送http 请求给服务器,请求投中带有if-modified-since或者if-none-match,于服务器端last-modify 和etag进行比较,如果为修改,返回304,读取浏览器渲染,如果发现修改,返回200,返回内容包装在消息体中,缓存协商,渲染
Expires cache-control last-modify etag的区别
Expires 是http1.0,目前已过期,为了兼容还带有expires
Cache-control 取代expires,带有更多的规则,max-age publice等
Last-modify 和etag 都是用来的标示文件是否被修改过,多用etag,如果同时出现,etag的优先级大于last-modify
几种加载js的方法
各种方式各有优缺点,比如能否跨域、是否会阻塞其它资源的下载(能否并行下载)、能否管理控制执行顺序、耗费的资源、是否兼容各大浏览器等。
方法 |
说明 |
XHR Eval |
通过 Ajax 方式获取代码,并通过 eval 方式执行代码。 |
XHR Injection |
通过 Ajax 方式获取代码,并在页面上创建一个 script 元素,将 Ajax 取得的代码注入。 |
Script in Iframe |
通过 iframe 加载 js。 |
Script DOM Element |
使用 JavaScript 动态创建 script DOM 元素并设置其 src 属性。 |
Script Defer/Async |
严格来说,这一条不算是动态加载外部脚本的方法,但很多动态加载外部脚本的方法里都会用到 sctipt 的 defer 或 async 属性,所以也把它单独列在这儿。这个方法利用 script 的 defer 属性,让脚本“推迟”执行,不阻塞页面加载,或者设置 async 属性,让脚本异步执行。遗憾的是这两个属性不是所有浏览器都支持。 |
document.write Script Tag |
通过 document.write 把 HTML 标签 script 写入到页面中。 |
cache trick |
先使用自定义的 script 的 type 属性(如 <script type=”text/cache” …),甚至使用 Image、Object 等 HTML 对象将 js “预下载”(下载到浏览器缓存里),等真正需要执行对应代码时再将它真正地插入页面中。 |
Web Worker |
部分浏览器支持 web worker 功能,可以创建一个 worker 在后台工作,包括加载外部脚本。 |
Bigpipe的原理
Bagpipe还正在学习中,bigpipe遵从的优化原则是尽早刷新输出缓冲 。浏览器和服务器可以并行同时工作。
Css选择器的性能
看到高性能网站建设那本书,关于css选择器的性能,发现之前我对css选择器的选择过程的认识是完全错误的,css选择器是从右向左匹配的,而不是从左向右匹配。
Localstorage 的性能问题
- localStorage 是同步的 (会阻塞渲染)
- localstorage存储的内容是存储在磁盘上的,所以每次读取开销很大,使用localstorage的时候应尽可能减少读取次数,增加读取的内容