实践一下前端性能分析
一、浏览器并行下载数量
浏览器的并发请求数目限制是针对同一域名的。
同一时间针对同一域名下的请求有一定数量限制,超过限制数目的请求会被阻塞。
所以我们经常能看到不同静态资源会有不同域名,例如图片、JavaScript、CSS等。
HTTP1.1与HTTP1.0,限制的数量还不一样。
1)HTTP1.1
先来看看browserscope网上的数量限制的统计结果,比IE6、IE7那会儿进步了很多。
接下来做一个对比,分别是一个域名和两个域名,分别加载图片。
当一个域名的时候最多只能并发6个请求,而两个域名的时候能并发10个请求。
2)长连接
由于长连接的关系,HTTP1.1建议每个服务器建立少量的连接。
如果浏览器支持 keep-alive(长连接),它会在请求的包头中添加:
长连接的原理是使用同一个TCP连接来发送和接收多个HTTP请求/应答,而不是为每一个新的请求/应答打开新的连接的方法。
当客户端发送另一个请求时,它会使用同一个连接。这一直继续到客户端或服务器端认为会话已经结束,其中一方中断连接。
下图左边每次请求后都会断开,右边就是请求后不会马上断开。
所以想要高并发量还可以降级到HTTP1.0,不过具体情况如何,我还没试验过。
3)Cookie-free Domains
在YSlow中有23条规则,第20条就是"Use Cookie-Free Domains for Components"。
在请求下载静态小图片、静态小文件的时候,浏览器会把它当成普通请求一样,在request的header信息里附加cookie信息。
如果每个header都附加1kB的cookie,那么对于一个有50个小文件的复杂网页来讲,就白白增加了50kB的传输量。
网上有很多相关的解决方案,可以尝试一下。
二、行内脚本阻塞并行下载
览器会保持css和js的解析顺序,如果把行内脚本放在样式表之后,会明显地延迟资源的下载(结果是样式表下载完成并且行内脚本执行完毕时,后续资源才能开始下载)。
这是因为行内脚本可能含有依赖于样式表中样式的代码,比如document.getElementsByClassName()。
行内脚本就是将脚本直接写在HTML页面中。
下面通过Chrom的工具查看下:
再来看看ui.png这个请求的详细情况,可以参考下Google中的文档,不过需要翻一下才能看到。
Stalled:浏览器得到要发出这个请求的指令,到请求可以发出的等待时间,一般是代理协商、以及等待可复用的TCP连接释放的时间,不包括DNS查询、建立TCP连接等时间等。
Request sent:请求第一个字节发出前到最后一个字节发出后的时间,也就是上传时间。
Waiting(TTFB) :请求发出后,到收到响应的第一个字节所花费的时间(Time To First Byte)。
Content Download:收到响应的第一个字节,到接受完最后一个字节的时间,新航道托福就是下载时间。
的确出现了延时下载,我将"script"标签去掉后,看到的确是并行下载的。
三、图像优化
平时就会做图像优化,例如制作Sprite图等。这里是介绍下压缩图片。
关于压缩的原理,涉及到些算法,可以上网查询下。
网友Jia在《图片原理与优化》说:
常见的格式中JPG、PNG、GIF亦属于位图,所以它们的数据结构大致相同,只是每一种图片格式都有不同的压缩算法,不同的扫描方式,但是优化的方法都有一个共同点,都是围绕着每个像素颜色值来下手。
1)工具
公司现在开发都用gulp构建工具,里面就有个插件"gulp-image",用这个工具压png图片,能压掉很多,jpg就不多了。
关于构建工具可以参考《前端自动化构建工具gulp记录》
网上还提供很多在线工具,例如国外的tinypng,国内的tuhaokuai。
下图来自于tinypng网,国宝熊猫帮我压缩了54%的质量,不过这个网站我上了好久才上去。
2)webP
WebP,是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。
根据 Google 的测试,无损压缩后的 WebP 比 PNG 文件少了 45% 的文件大小,即使这些 PNG 文件经过其他压缩工具压缩之后,WebP 还是可以减少 28% 的文件大小。
兼容性方面,Android兼容性较好,毕竟是自己的东西,不过IOS Safrai完全不支持,下图中显示中国的浏览器已经覆盖到了67.37%。
四、iframe
在多年前曾经写过一篇基础概念的iframe,叫《iframe的一些记录》。
一直能看到iframe的种种缺点,但是并没有通过数据表达出来,这次用数据说明一下。
1)阻塞onload事件
在"Iframes Blocking"这个页面中,通过iframe加载一个页面,这个页面要4秒后才加载完,直接导致的父页面也要4秒后才能加载成功。
2)脚本位于iframe之前
在"Script Before Iframe"这个页面中,script脚本标签写在了iframe之前。
图中红色框框中的就是iframe中的内容,的确被阻塞了。
后面又试验了一下将CSS放在iframe之前或之后,并不会被阻塞。
3)iframe中连接共享
在"Parent and Iframe Connections"这个页面中,父页面和iframe中的页面都包含了5张图片。
这五张图片并不是并行下载,而是有先后顺序的,红色方框中的图片来自于iframe。
五、CSS选择符
下面这些就是CSS选择符:
#toc { margin-left: 20px; }.chapter { font-weight: bold; }A { text-decoration: none; }H1 + #toc { margin-top: 40px; }#toc > LI { font-weight: bold; }#toc A { color: #444; }* { font-family: Arial; }[href="#index"] { font-style: italic; }[title~="Index"] { font-style: italic; }A:hover { text-decoration: underline; }
归纳下来有5种选择符,元素、关系、属性、伪类和伪对象选择符。
CSS选择符是从右向左匹配的,在MDN的《编写高效的 CSS》中介绍了几种高效CSS指南。
1)选择器测试结构
在"Selector Tests"页面中有6种写好的,页面中1000个那种结构。
1. Baseline设置了CSS类,但不会匹配
2. Tag就多了个A标签CSS设置
3. Class设置了A中的class属性
4. Child使用了关系选择符中的子选择符">"
5. Descendant使用了关系选择符中的包含选择符
6. Universal使用了通配符
2)耗时记录
Baseline | Tag | Class | Child | Descendant | Universal | |
CSS类 | .noclass0001 { background: #CFD; } background: #CFD; } | A { background: #CFD; } background: #CFD; } background: #CFD; } | .class0001 { background: #CFD; } background: #CFD; } | DIV > DIV > DIV > P > A.class0001 { background: #CFD; } background: #CFD; } | DIV DIV DIV P A.class0001 { background: #CFD; } background: #CFD; } | P.pclass0001 * { background: #CFD; } background: #CFD; } |
耗时 | 85ms | 63ms | 71ms | 101ms | 77ms | 501ms |
耗时 | 60ms | 67ms | 479ms | 185ms | 444ms | 76ms |
耗时 | 59ms | 1116ms | 64ms | 73ms | 67ms | 54ms |
耗时 | 69ms | 62ms | 68ms | 67ms | 62ms | 83ms |
耗时 | 52ms | 63ms | 68ms | 78ms | 68ms | 77ms |
耗时 | 60ms | 62ms | 72ms | 87ms | 67ms | 81ms |
去掉最高和最低后 平均耗时 | 62ms | 63.75ms | 69.75ms | 84.75ms | 69.75ms | 79.25 |
还有一个"create your own"自定义类:
还附赠了4个选择器:"A.class DIV","id > A",".class [href]","DIV:first-child"。