转:浏览器加载页面的过程与页面性能优化
本文是转帖,原文:http://www.baiduux.com/blog/2011/02/15/browser-loading/
发布日期:2011年2月15日
本文将探讨浏览器渲染的loading过程,主要有2个目的:
- 了解浏览器在loading过程中的实现细节,具体都做了什么
- 研究如何根据浏览器的实现原理进行优化,提升页面响应速度
由于loading和parsing是相互交织、错综复杂的,这里面有大量的知识点,为了避免过于发散本文将不会对每个细节都深入研究,而是将重点 放在开发中容易控制的部分(Web前端和Web Server),同时由于浏览器种类繁多且不同版本间差距很大,本文将侧重一些较新的浏览器特性
现有知识
除此之外还可以使用HTTP header中的X-DNS-Prefetch-Control来控制浏览器是否进行预解析,它有on和off两个值,更详细的信息请参考Controlling DNS prefetching
DNS优化的原理和方法
Yahoo和Google都有自己的建设高性能网站最佳实践, 我不做赘述, 需要了解的自行查阅资料:
- Yahoo的: Best Practices for Speeding Up Your Web Site
- Google的: Web Performance Best Practices
上面的最佳实践条例其实也就是我们常在YSlow和PageSpeed这两个Firefox的add-ons中看到的网站检测结果的参考标准.
而整个WPO其实是对浏览器(browser)的加载(load)和解析(parse)过程中的一些消耗行为进行优化, 而load和parse在整个浏览器工作过程中又互相纠结互相作用.
在这篇文字中讨论的更多是FE们能够伸手处理或者通过达成共识的方法来进行快速推动Tech们协助的一些事情.
OK, 我们慢慢把浏览器的工作过程掰细了看吧.
首先, 我们先整一个浏览器如何找到一个网站的简易工作原理 – DNS查询:
首先当用户在浏览器的地址栏中敲入了网站的网址 ( 比如: alibaba.com ) ,这时浏览器会首先通过访问的域名来定位到IP (DNS) 从而找到去哪里获取资源, 这时, 浏览器会依次进行如下查找:
1. 浏览器缓存 :
浏览器首先会在自己的缓存中查找有没有对应的域名 – IP匹配, 如果好运的话, 这里就可以直接尝试去访问资源了, 如果运气平平则往下走吧.
2. 系统缓存 :
浏览器缓存中没有命中, 浏览器会告诉操作系统:”嘿, 我在我自己口袋里没找到, 可能丢了, 我得去你那看看”, 然后, 一个系统进程(?)调取系统中的DNS缓存进行查询, 重复上一条的运气判断…
3. 路由器缓存 :
走到这, 运气还真不太好啊, 操作系统也没辙了, 那怎么办呢, 向路由去要要看吧… 重复运气判断…
4. ISP DNS缓存 :
好吧, 真不知道说运气好还是运气不好了, 不废话, 去ISP (网络提供商) 的DNS缓存服务器中寻找了, 一般情况下, 在ISP端的缓存中都能找到相应的缓存记录了, 不该这么背了, 或者… 您的ISP有够菜…
5. 递归搜索…
最无奈的情况发生了, 在前面都没有办法命中的DNS缓存的情况下, ISP的DNS服务器开始从root域名服务器开始进行递归, 顺序是从.com顶级域名服务器到alibaba的域名服务器, 再没找到…好吧, 您认为您要去的网站真的公开存在么…?
要强调的是, 不只是对网站第一次的域名访问需要做这样一次查询工作, 在对页面中的资源引用的域名解析时一样会有这样的一系列工作. 最明显的就是启用全新域名来做静态资源存储服务时, 基本上上述的1 – 5个步骤都得走上几遍. 才能让新域名在各DNS缓存服务器上留下记录.
在这个话题上, 关于DNS的类似系统级的解决方案不是FE能够控制得了的, 我们q可以在涉及到DNS时有些小Tips来从中做些事情.
好吧, 第一项.DNS相关的优化:
常规实践 : DNS解析的复杂性决定了不当的使用多域名获取资源会造成不必要的性能开销. 在WPO中, 很多优化工作是很艺术的, 在DNS和HTTP这两方面优化是就可以看到这个神奇的艺术性:
DNS的优化, 当然是尽可能少的造成DNS查询开销, 而在HTTP优化的策略中有一项优化措施是避免单域名下连接数的缺陷来进行资源多通道下载, 实施的细节会在<HTTP优化的原理和方法> 中详细介绍, 在这里只是简单的提一下, 静态资源多域名服务可以绕过浏览器单域名载入资源时并行连接数的限制, DNS优化需要我们尽可能少的域名解析, HTTP优化时需要我们适当的使用多域名服务, 那怎么样让两个优化实践都能够比较好的实施呢? [todo]
优雅降级 : 在某些现代浏览器 ( Google Chrome, Firefox 3.5+ ) 中, 已经能够支持DNS的预取了, 怎么个预取呢? 就是在浏览器加载网页时, 对网页中的<link>或者<a>的href属性中的域名进行后台的预解析(上文中的 1- 5步), 并且将解析结果缓存在浏览器端, 当用户在真正点击链接时, 省去在当下的DNS解析消耗, 把这个消耗过程转嫁到用户无法感知的浏览过程中去.
第一, 现代浏览器已经支持且默认打开了DNS Prefetch的功能. 当然也可以通过浏览器的配置来管理该功能:
用Firefox3.5+可以这样: 浏览器默认就打开了HTTP协议下的DNS预取功能, 默认关闭HTTPS协议下的DNS预取功能, 可通过 about:config 的
network.dns.disablePrefetch
和network.dns.disablePrefetchFromHTTPS
<两个选项来控制两种协议下的预取功能.
Chrome管理DNS Prefetch方法暂时缺少.
第二,
可以通过用meta信息来告知浏览器, 我这页面要做DNS预取:
<meta http-equiv="x-dns-prefetch-control" content="on" />
第三,可以
使用link标签来强制对DNS做预取:
<link rel="dns-prefetch" href="http://www.alibaba.com/" />
[todo DEMO]
扩展阅读:
- Controlling DNS prefetching in Firefox
- DNS Prefetching for Firefox (blog post)
- DNS Prefetching in Chrome
link prefetching in HTML5
另, 小康(lazyKang)同学发现一个神奇的现象:
在一次无缓存访问中, 在一个并行下载通道内, 就算是同域名的情况, 也会造成DNS并行解析的消耗…
DNS预解析一次, 应该就能避免这样的问题, 空了做个DEMO试试看.
CDN
本文不打算详细讨论这个话题,感兴趣的读者可以阅读Content delivery network
在性能方面与此相关的一个问题是用户可能使用自定义的DNS,如OpenDNS或Google的8.8.8.8,需要注意对这种情况进行处理
link prefetch
<link rel="prefetch" href="http://">
但这种写法目前并没有成为正式的标准,也只有Mozilla真正实现了该功能,可以看看Link prefetching FAQ
WebKit也在尝试该功能,具体实现是在HTMLLinkElement的process成员函数中,它会调用ResourceHandle::prepareForURL()函数,目前从实现看它是仅仅用做DNS预解析的,和Mozilla对这个属性的处理不一致
对于不在当前页面中的链接,如果需要预下载后续内容可以用js来实现,请参考这篇文章Preload CSS/JavaScript without execution
预下载后续内容还能做很多细致的优化,如在Velocity China
2010中,来自腾讯的黄希彤介绍了腾讯产品中使用的交叉预下载方案,利用空闲时间段的流量来预加载,这样即提升了用户访问后续页面的速度,又不会影响到高峰期的流量,值得借鉴
预渲染
不得不说Chrome的性能优化做得很细致,各方面都考虑到了,也难怪Chrome的速度很快
http
在网络层之上我们主要关注的是HTTP协议,这里将主要讨论1.1版本,如果需要了解1.0和1.1的区别请参考Key Differences between HTTP/1.0 and HTTP/1.1
header
header大小
header的扩展属性
header中有些扩展属性可以用来保护站点,了解它们是有益处的
- X-Frame-Options
- 这个属性可以避免网站被使用frame、iframe的方式嵌入,解决使用js判断会被var location;破解的问题,IE8、Firefox3.6、Chrome4以上的版本都支持
- X-XSS-Protection
- 这是IE8引入的扩展header,在默认情况下IE8会自动拦截明显的XSS攻击,如query中写script标签并在返回的内容中包含这项标签,如果需要禁止可以将它的值设为0,因为这个XSS过滤有可能导致问题,如IE8 XSS Filter Bug
- X-Requested-With
- 用来标识Ajax请求,大部分js框架都会加入这个header
- X-Content-Type-Options
- 如果是html内容的文件,即使用Content-Type: text/plain;的header,IE仍然会识别成html来显示,为了避免它所带来的安全隐患,在IE8中可以通过在header中设置X- Content-Type-Options: nosniff来关闭它的自动识别功能
使用get请求来提高性能
首先性能因素不应该是考虑使用get还是post的主要原因,首先关注的应该是否符合HTTP中标准中的约定,get应该用做数据的获取而不是提交
之所以用get性能更好的原因是有测试表明,即使数据很小,大部分浏览器(除了Firefox)在使用post时也会发送两个TCP的packet,所以性能上会有损失
连接数
在HTTP/1.1协议下,单个域名的最大连接数在IE6中是2个,而在其它浏览器中一般4-8个,而整体最大链接数在30左右
使用多个域名可以提高并发,但前提是每个域名速度都是同样很快的,否则就会出现某个域名很慢会成为性能瓶颈的问题
cache
主流浏览器都遵循http规范中的Caching in HTTP来实现的
从HTTP cache的角度来看,浏览器的请求分为2种类型:conditional requests 和 unconditional requests
unconditional请求是当本地没有缓存或强制刷新时发的请求,web server返回200的heder,并将内容发送给浏览器
而conditional则是当本地有缓存时的请求,它有两种:
- 使用了Expires或Cache-Control,如果本地版本没有过期,浏览器不会发出请求
- 如果过期了且使用了ETag 或Last-Modified,浏览器会发起conditional请求,附上If-Modified-Since或If-None-Match的 header,web server根据它来判断文件是否过期,如果没有过期就返回304的header(不返回内容),浏览器见到304后会直接使用本地缓存中的文件
以下是IE发送conditional requests的条件,从MSDN上抄来
- The cached item is no longer fresh according to Cache-Control or Expires
- The cached item was delivered with a VARY header
- The containing page was navigated to via META REFRESH
- JavaScript in the page called reload on the location object, passing TRUE
- The request was for a cross-host HTTPS resource on browser startup
- The user refreshed the page
简单的来说,点击刷新按钮或按下F5时会发出conditional请求,而按下ctrl的同时点击刷新按钮或按下F5时会发出unconditional请求
前进后退的处理
浏览器会尽可能地优化前进后退,使得在前进后退时不需要重新渲染页面,就好像将当前页面先“暂停”了,后退时再重新运行这个“暂停”的页面
不过并不是所有页面都能“暂停”的,如当页面中有函数监听unload事件时,所以如果页面中的链接是原窗口打开的,对于unload事件的监听会影响页面在前进后时的性能
在新版的WebKit里,在事件的对象中新增了一个persisted属性,可以用它来区分首次载入和通过后退键载入这两种不同的情况,而在Firefox中可以使用pageshow和pagehide这两个事件
unload事件在浏览器的实现中有很多不确定性因素,所以不应该用它来记录重要的事情,而是应该通过定期更新cookie或定期保存副本(如用户备份编辑文章到草稿中)等方式来解决问题
cookie
浏览器中对cookie的支持一般是网络层库来实现的,浏览器不需要关心,如IE使用的是WinINET
p3p问题
在IE中默认情况下iframe中的页面如果域名和当前页面不同,iframe中的页面是不会收到cookie的,这时需要通过设置p3p来解决,具体可以察看微软官方的文档,加上如下header即可
P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"
这对于用iframe嵌入到其它网站中的第三方应用很重要
编码识别
页面的编码可以在http header或meta标签中指明,对于没有指明编码的页面,浏览器会根据是否设置了auto detect来进行编码识别(如在chrome中的View-Encoding菜单)
关于编码识别,Mozilla开源了其中的Mozilla Charset Detectors模块,感兴趣的可以对其进行学习
<meta charset="utf-8">
需要注意不设定编码会导致不可预测的问题,应尽可能做到明确指定
chunked
在具体实现上,php中可以通过flush函数来实现,不过其中有不少需要注意的问题,如php的配置、web server、某些IE版本的问题等,具体请参考php文档及评论
另外Facebook所使用的BigPipe实际上是在应用层将页面分为了多个部分,从而做到了服务端和浏览器计算的并行
keepalive
keepalive使得在完成一个请求后可以不关闭socket连接,后续可以重复使用该连接发送请求,在HTTP/1.0和HTTP/1.1中都有支持,在HTTP/1.1中默认是打开的
keepalive在浏览器中都会有超时时间,避免长期和服务器保持连接,如IE是60秒
另外需要注意的是如果使用阻塞IO(如apache),开启keepalive保持连接会很消耗资源,可以考虑使用nginx、lighttpd等其它web server,具体请参考相关文档,这里就不展开描述
pipelining
可惜目前绝大部分浏览器在默认情况下都不支持,已知目前只有opera是默认支持的,加上很多网络代理对其支持不好导致容易出现各种问题,所以并没有广泛应用
SPDY
SPDY是google提出的对HTTP协议的改进,主要是目的是提高加载速度,主要有几点:
- Mutiplexed streams
- 可以在一个TCP中传输各种数据,减少链接的耗时
- Request prioritization
- 请求分级,便于发送方定义哪些请求是重要的
- HTTP header compression
- header压缩,减少数据量
frame
从实现上看,frame类(包括iframe和frameset)的标签是最耗时的,而且会导致多一个请求,所以最好减少frame数量
resticted
如果要嵌入不信任的网站,可以使用这个属性值来禁止页面中js、ActiveX的执行,可以参考msdn的文档
<iframe security="restricted" src=""></iframe>
javascript
加载
<script src="a.js"></script>
浏览器对它的处理主要有2部分:下载和执行
下载在有些浏览器中是并行的,有些浏览器中是串行的,如IE8、Firefox3、Chrome2都是串行下载的
执行在所有浏览器中默认都是阻塞的,当js在执行时不会进行html解析等其它操作,所以页面顶部的js不宜过大,因为那样将导致页面长时间空白,对于这些外链js,有2个属性可以减少它们对页面加载的影响,分别是:
- async
- 标识js是否异步执行,当有这个属性时则不阻塞当前页面的加载,并在js下载完后立刻执行
- 不能保证多个script标签的执行顺序
- defer
- 标示js是否延迟执行,当有这个属性时js的执行会推迟到页面解析完成之后
- 可以保证多个script标签的执行顺序
下图来自Asynchronous and deferred JavaScript execution explained,清晰地解释了普通情况和这2种情况下的区别
需要注意的是这两个属性目前对于内嵌的js是无效的
而对于dom中创建的script标签在浏览器中则是异步的,如下所示:
var script = document.createElement('script'); script.src = 'a.js'; document.getElementsByTagName('head')[0].appendChild(script);
为了解决js阻塞页面的问题,可以利用浏览器不认识的属性来先下载js后再执行,如ControlJS就是这样做的,它能提高页面的相应速度,不过需要注意处理在js未加载完时的显示效果
document.write
document.write是不推荐的api,对于标示有async或defer属性的script标签,使用它会导致不可预料的结果,除此之外还有以下场景是不应该使用它的:
另外,可以使用ADsafe等方案来保证嵌入第三方广告的安全,请参考如何安全地嵌入第三方js – FBML/caja/sandbox/ADsafe简介
script标签放底部
将script标签放底部可以提高页面展现给用户的速度,然而很多时候事情并没那么简单,如页面中的有些功能是依赖js的,所以更多的还需要根据实际需求进行调整
传输
js压缩可以使用YUI Compressor或Closure Compiler
gwt中的js压缩还针对gzip进行了优化,进一步减小传输的体积,具体请阅读On Reducing the Size of Compressed Javascript
css
@import
使用@import在IE下会由于css加载延后而导致页面展现比使用link标签慢,不过目前几乎没有人使用@import,所以问题不大,具体细节请参考don’t use @import
selector的优化
浏览器在构建DOM树的过程中会同时构建Render树,我们可以简单的认为浏览器在遇到每一个DOM节点时,都会遍历所有selector来判断这个节点会被哪些selector影响到
另一个比较好的方法是从架构层面进行优化,将页面不同部分的模块和样式绑定,通过不同组合的方式来生成页面,避免后续页面顶部的css只增不减,越来越复杂和混乱的问题,可以参考Facebook的静态文件管理
工具
Browserscope
之前提到的http://www.browserscope.org收集了各种浏览器参数的对比,如最大链接数等信息,方便参考
Navigation Timing
Navigation Timing是还在草案中的获取页面性能数据api,能方便页面进行性能优化的分析
目前这个api较新,目前只在一些比较新的浏览器上有支持,如Chrome、IE9,但也占用一定的市场份额了,可以现在就用起来
boomerang
另外就是通过静态图片来衡量带宽和网络延迟,具体可以看boomerang
检测工具
reference
- Browser Performance Wishlist
- HTML5
- Testing Page Load Speed
- Technically speaking, what makes Google Chrome fast?
- Optimizing Page Load Time
- An Engineer’s Guide to Bandwidth
- An Engineer’s Guide to DNS
- EricLaw’s IEInternals
- Internet Explorer Platform for Privacy Preferences (P3P) Standards Support Document
- COMET Streaming in Internet Explorer
- Internet Explorer Cookie Internals (FAQ)
- Fiddler PowerToy – Part 2: HTTP Performance
- Frontend SPOF
- XMLHttpRequest (XHR) Uses Multiple Packets for HTTP POST?
- WebKit Page Cache I – The Basics
- WebKit Page Cache II – The unload Event
转载于:https://www.cnblogs.com/stephenykk/p/3670002.html
转:浏览器加载页面的过程与页面性能优化相关推荐
- 浏览器加载网页的过程
简单的说明: 1.浏览器通过URL访问服务器地址 2.通过DNS访问具体IP 3.TCP/IP 通信, 返回http请求 4.前台解析html 5.加载JS 6.构建DOM节点,组合CSS 7.浏览器 ...
- 浏览器加载渲染网页过程解析-总结
js的加载会阻塞此js文件下面的图片的加载,但不会阻塞其他js,css的加载 js的加载会阻塞浏览器的渲染,需要等待js加载执行完毕后才可以继续渲染 js的加载虽然是异步进行的,但是执行仍然会保持从上 ...
- html轮播图速度加快,jQuery按需加载轮播图(web前端性能优化)
引言 关于幻灯轮播图,想必大家都不陌生,尤其是基于 jQuery 的,插件.代码网上一搜一大堆,但是真正符合自己需求的几乎没有,所以我要打造一个符合自身需求,经得起广大网民考验的 jQuery 轮播图 ...
- iMobile中加载大数据量的矢量数据性能优化方法有哪些
作者:xinxin 随着移动技术的发展,GIS行业中移动项目越来越多.在移动应用中不仅要对接在线的服务数据,还要加载各种本地的业务数据,GIS数据的量一般很大,而移动设备的内存有限,加载本地大数据量的 ...
- 浏览器加载、解析、渲染的过程
最近在学习性能优化,学习了雅虎军规 ,可是觉着有点云里雾里的,因为里面有些东西虽然自己也一直在使用,但是感觉不太明白所以然,比如减少DNS查询,css和js文件的顺序.所以就花了时间去了解浏览器的工作 ...
- 从输入 URL 到页面加载完的过程中都发生了什么事情 —— 网络优化篇
转自从输入 URL 到页面加载完的过程中都发生了什么事情 -- 网络优化篇 想到这不就是我这两年来研究的东西么,于是就接受一下挑战.网上已经有很多版本的答案了.这道题可以从浏览器端,网络传输和服 ...
- 浏览器加载和渲染html的顺序
1.浏览器加载和渲染html的顺序 浏览器加载和渲染html的顺序 IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 在渲染到页面的某一部分时,其上面的所有部分都已经下载完成 ...
- 加载如下html 写出输出顺序,浏览器加载和渲染html的顺序-结论篇
我只转载觉得可以使用的. 1.浏览器加载和渲染html的顺序 1.IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 2.在渲染到页面的某一部分时,其上面的所有部分都已经下载完 ...
- 浏览器加载解析渲染机制的全面解析
(注1:如果有问题欢迎留言探讨,一起学习!本文首发于我的简书,转载请注明出处,喜欢可以点个赞哦!) (注2:更多内容请查看我的目录.) 1. 简介 在前面一篇文章中,讲到了用户从输入url到看到页面的 ...
最新文章
- 请编程实现:产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复(百度了一下,get一种高性能算法,非递归)...
- python 颤音_自成一派,这个作曲大师确实名副其实!
- pytorch中tensorboard使用
- PHP 实现归并排序算法
- 关于开发中的常用手段(个人建议)
- php 显示当前年月日时分秒,php 获取当前前后年、月、星期、日、时分秒的时间...
- Bootstrap3 正文文本样式
- android 两列菜单,【Android】实战开发之ListView同一个item显示2列的实现方法(仿2列商品列表)...
- 如何用一句话证明你搞 IT(挨踢)的?
- python微博接口_python调用微博api接口
- excel中用正则匹配_Excel 使用正则表达式提取数据
- 打印机驱动无法安装到计算机是,电脑打印机无法安装驱动的解决方法
- 数论(继续补充)(gcd + lcm + qpow + prime+qmul)
- eu5,eu7,ex3,ex5安装第三方app
- iOS 使用oc 版本的Lottie 库
- openssl命令查看证书有效期_kubeadm初始化k8s集群延长证书过期时间
- 肝素-PEG2000-PBA肝素-PEG-苯硼酸|NHS-PEG-PBA活化脂-聚乙二醇-苯硼酸|齐岳定制服务
- 240次方在线计算机,0.05的240次方是多少
- 演说演讲PPT模板推荐
- edup无线网卡驱动安装linux,802.11n无线网卡驱动-edup 802.11n驱动下载最新版-802.11n驱动西西软件下载...
热门文章
- 网络编程基础知识详解
- PHP后端发送Ajax情书,分享某平台上面发布的计算机编程情书
- 微信扫码 - 关注公众号后网站自动注册并登录的实现
- jsqlparser mysql_java sql解析器比较druid sql parser vs jsqlparser vs fdb-sql-parser
- python设计程序基础、李东方教材答案_Python程序设计基础(第2版)
- 大连理工大学计算机原理实验报告,大连理工大学计算机原理实验报告.pdf
- Bugku Web eval
- VC++/MFC消息映射机制(1):MFC消息映射原理
- (翻译)标签模式(Tagging)
- 高德推出查岗功能_打尽渣男渣女的查岗神器?高德家人地图实测