[关闭]
@fengfeng 2015-09-15T03:42:10.000000Z 字数 6399 阅读 3232

浏览器是如何工作的?

浏览器 browser parse render localcache


当我们从开始在地址栏输入url到最后浏览器把页面展示给我们,这中间浏览器都做了哪些事情?

Local cache

首先浏览器会根据url查找本地缓存,看是否本地缓存中存在该url的内容,如果不存在,则向服务器请求该url的内容,否则:


页面请求merge.js请求过程

优化点:

  • 给静态资源设置适当的缓存时间 expire:xxx /cache-control:max-age=xxx
  • 返回的http头带Last-Modified/Etag,当内容过期时,进行条件查询请求;

进一步阅读

浏览器缓存机制

服务器与浏览器缓存协商控制机制的总结

DNS query

当浏览器向服务器发送请求,请求一个url对应的资源时,首先是检查是否本地有服务器host的ip,如果没有通过DNS查询来获取服务器的ip。

无线网络的现状:

  • 2G:一般只有10KB/S下行和1KB/S左右的上行速度,延迟基本不低于400ms;
  • 3G网络:一般为下行100-200KB/S,上行10-100KB/S,延迟0-400ms,带宽方面基本逼近2M有线网络,但延迟较高,稳定性不够

DNS查询耗时:

  • 在相对较快速的有线网络环境下,平均值为数十毫秒左右;
  • 2G网络环境下,平均值在几百毫秒左右;
  • 在网络很差的移动环境下,平均值达到几秒左右

优化点:

  • 让浏览器提前查询dns:dns-prefetch
  • 减少页面中的资源的域名/直接ip
  1. <link rel="dns-prefetch" href="pic2.58.com" >

Connect To Server 和服务器建立连接

根据DNS查询得到ip+url中的端口80,向服务器发起TCP连接。
因为用户和服务器之间的距离(不仅是物理距离,还有网络链路距离,以及跨运营商中转等)不同,建立连接的时间不同。

优化点:

  • 采用CDN,让用户与它最近的服务器建立连接

TCP 3 handshake TCP建立连接3次握手

TCP建立连接3次握手

TCP建立连接3次握手

因为每建立一次TCP连接,都要进行3次握手,建连成本大;

优化点:

  • 减少建立连接的次数:merge CSS/js/image
  • 减少建立连接的次数:remove empty src/href/URL
  • 减少建立连接的次数:keep-alive

Send HTTP Request 发送http请求

当浏览器发送http请求头时,会把相关一些信息发送,这些信息包括:UA,Localsetting,Referer,Cookie等

优化点:

  • 能用get,不用post请求url,post至少发送两个包
  • 减少发送的http header的大小:避免发送不需要的cookie,静态资源放到独立域名的服务器上
  • 减少发送的http header的大小:缩短url的长度,不同浏览器和服务器对url的长度也有限制
  1. GET / HTTP/1.1
  2. Host:www.taobao.com
  3. User-Agent:Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.17) Gecko/20110420Firefox/3.6.17
  4. Accept:text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
  5. Accept-Encoding:gzip,deflate
  6. Accept-Language:en-us,en;q=0.5
  7. Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.
  8. Keep-Alive:115
  9. Connection: keep-alive
  1. HTTP/1.1 200 OK
  2. Server: nginx
  3. Date: Thu, 12May 2011 11:02:36 GMT
  4. Content-Type:text/html; charset=GB2312
  5. Transfer-Encoding:chunked
  6. Connection:keep-alive

进一步阅读

IE6、IE7、IE8 URL长度支持问题

HTTP中的URL长度限制

服务器的工作

服务器接到请求后,根据请求的url和数据等,经过一系列运算,拼出一个大字符串就是网页的内容返回给浏览器

路由转发

获取数据

返回文件/渲染模版

输出内容

浏览器是边下载边解析

优化点:

  • bigPipe,flush buffer early 不必等所有数据都拿到再拼页面,有一点就输出,早点刷新缓冲区,节省的是等待服务器响应的时间

传统页面展现

传统页面展现

bigpipe页面展现

bigpipe页面展现

HTTP Response Header

  • 304 Not Modified 浏览器还是利用老的缓存数据
  • 200 Ok 新的内容

HTTP Response Body

返回的数据越少,传输的越快

优化点:

  • 返回的内容进行压缩HTML/CSS/js/img compres gzip
  • 异步刷新,不需要返回全部内容,只返回变化的部分,ajax等

浏览器处理过程

浏览器处理过程中的每一个步骤:

  1. 解析HTML/SVG/XHTML,build DOM树
  2. 解析CSS,build CSSOM树
  3. build rendering tree. Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。
  4. layout/reflow.计算每个Frame(也就是每个Element)的位置,这又叫layout和reflow过程
  5. paint. 最后通过调用操作系统Native GUI的API绘制

Alt text

parse content

根据http响应返回的数据根据页面编码进行解码,而浏览器判断编码主要是依据以下方法:

  1. HTTP 头中的 Content-Type: text/html; charset= 信息,这一般有最高的优先级;
  2. 网页本身 meta header 中的 Content-Type 信息的 charset 部分,对于 HTTP 头未指定编码或者本地文件,一般是这么判断;
  3. 假如前两条都没有找到,浏览器菜单里一般允许用户强制指定编码;
    部分浏览器 (比如 Firefox) 可以选择编码自动检测功能,使用基于统计的方法判断未定编码。
  4. 编码确定后,网页就被解码成了 Unicode 字符流,可以进行HTML 解析.

解析返回的内容,一个字符一个字符解析,边下载边解析

优化点:

  • 通过HTTP头信息或meta标签尽早指定正确的字符编码
  • 去除HTML/CSS/js/中的空白字符

解析过程遇到css,js等资源,就会发起请求,下载css,js,..,但是浏览器同一个域名并行下载个数有限制

优化点:

  • js/css 多域名存放,增加并行下载的个数,注意与cdn查询成本从和浏览器处理性能之间的平衡

进一步阅读

各浏览器的并行连接数(同域名)

build dom tree

字节(Bytes) -> 字符(characters) -> 标记(tokens) -> 节点(nodes) -> 对象模型
Alt text
1. 转换(Conversion): 浏览器从磁盘或者网络上读取HTML的原始字节,然后根据指定的编码规则转换成单独的字符(比如按UTF-8编码)。
2. 标记分解(Tokenizing):浏览器将字符串按照W3C HTML5标准转换成确定的标记,比如、以及其他带尖括号的字符。每个标记都有特定的意义以及一套规则。
3. 词法分析(Lexing):分解出来的标记被转换成能定义其属性和规则的对象。
4. DOM 构造: 最终由于HTML标记创建出来的对象被关联到一个树形数据结构。这颗树会反映在原先标签里定义的父子关系,比如HTML对象就是body对象的父对象,body对象又是paragraph对象的父对象等等。

优化点:

  • 删除无用的html标签,精简html结构,尽量减少不必要的dom的深度

进一步阅读

谷歌 Web 开发最佳实践手册(4.1.1):创建对象模型

build CSSOM tree

当css下载完成后,与HTML一样,进行构建cssom:
cssom-construction

cssom-tree

优化点:

  • 避免通配选择器
  • 删除多余的修饰语
  • 避免使用后代选择器,特别是那些指定多余祖先的
  • 使用class选择器代替后代选择器
  • 在IE中避免对非链接元素应用:hover
  • 避免CSS expressions

进一步阅读

谷歌 Web 开发最佳实践手册(4.1.1):创建对象模型

优化浏览器渲染

对《优化浏览器渲染》的补充

Mozilla里的高效CSS规则

build render tree

浏览器只有同时具备DOM(Document Object Mode,文档对象模型)和CSSOM(CSS Object Model,CSS对象模型)才能来构造渲染树。

Alt text

为了创建渲染树,浏览器大致需要如下的步骤:

  1. 从DOM树的根节点开始,遍历所有的可视节点
  2. 有些不可见元素(比如脚本标签,元数据标签之类)会被忽略,因为它们不影响渲染的结果
    有些通过CSS隐藏掉的元素也会被忽略,比如上图中的span元素。由于该元素上显式地设置了属性“display:none”,所以不会出现在渲染树上。(CSS中“visibility:hidden”和“display:none”是不同的。前者将元素隐藏起来,但是隐藏元素仍然会在页面最终的布局中占据相应的空间(其实就是一块空白)。然而后者会直接将元素从渲染树中删除,不仅不可见,也不属于最终布局的一部分)
  3. 对于每个可视节点,从CSSOM中寻找对应的样式规则,并付诸节点
  4. 输出可视的节点,以及每个节点计算出来的样式

谷歌 Web 开发最佳实践手册(4.1.2):渲染树结构、布局和绘制

浏览器即使已经处理好了某些页面内容,只要CSSOM没有构建好,便不会进行渲染,CSS是渲染过程中的阻塞性资源

js前面的css会阻塞js的执行

js执行阻塞页面的解析,domtree的构建

css优化点:

  • gzip,提高传输速度,css尽早加载
  • 优化css代码,css代码瘦身,压缩,去除冗余
  • put css head,js bottom

js优化点:

  • js压缩,gzip,提高传输速度
  • put css head,js bottom
  • 页面中不要插入js的代码,根据实际情况对js进行defer/asyn,或创建标签异步加载js;
  • 代码优化,使用id选择器,使用标准的css选择器,
    〉* 对常用变量暂存
  • 对长时间执行的代码用定时器来分片执行或html5 worker

reflow

我们已经计算了什么节点是可视的以及它们对应的样式是什么,但是我们还没有计算它们在当前设备中准确的位置和尺寸。这正是布局阶段要做的的工作,该阶段在英语中也被称为“回流”(reflow)。布局阶段的输出结果称为 “盒模型”(box model)。盒模型精确表达了窗口中每个元素的位置和大小,而且所有的相对的度量单位都被转化成了屏幕上的绝对像素位置。

paint

最后阶段,已经知道了哪些节点是可视的、它们的样式和它们的几何外观,我们终于能够将这些信息渲染为屏幕上每个真实的像素点了。这个阶段称为“绘制”,或者“格栅化”(rasterizing)。一旦布局阶段完成,浏览器便开始绘制阶段,将渲染树转化为屏幕上的每个像素点

show

通过调用操作系统Native GUI的API绘制每一个像素点,更新显存,给显示器发送信号,显示器根据得到的信号进行显示。
如果浏览器刷新频率为60hz,那么定时器的时间小于1/60s(16.666..ms)就没有意义。

优化点:

  • 设置适当的定时时间
  • 使用requestAnimationFrame(rAF)来代替定时器动画
  • 利用GPU加速

进一步阅读

Javascript高性能动画与页面渲染

High Performance Animations

Accelerated Rendering in Chrome
Jank Busting for Better Rendering Performance

Leaner, Meaner, Faster Animations with requestAnimationFrame

Optimizing Visual Updates

GPU Accelerated Compositing in Chrome

reflow & repaint

以下这些会引起reflow & repaint:

  1. 改变文字大小
  2. 应用新的样式或者修改任何影响元素外观的属性,修改class/style
  3. 激活伪类,如:hover
  4. DOM元素的添加、修改(内容)、删除( Reflow + Repaint),添加新的页面内容,例如输入框输入文字等

  5. 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE))

  6. 当一个元素的外观被改变,但没有改变布局的情况下发生,如改变visibility、outline、前景色,scroll等,会引起repain
  7. Resize浏览器窗口、滚动页面,
  8. 没有指定的图片尺寸,或者如果指定的尺寸不符合图片的实际尺寸,一旦图片下载,浏览器将需要reflows和重新绘制页面
  9. 在页面中间通过style或外链加载样式,也会导致reflow
  10. 不指定页面的编码,浏览器开始渲染页面之后发现指定的编码设定与其设定或默认值不同,都会导致重新解析文档并重绘页面。如果编码的变化影响到了外部资源(例如css\js\media),浏览器甚至会重新对资源进行请求;

优化点:

  • 尽可能限制reflow的影响范围,避免在document上直接进行频繁的DOM操作,如果确实需要可以采用off-document的方式进行
    1. 先将元素从document中删除,完成修改后再把元素放回原来的位置
    2. 将元素的display设置为”none”,完成修改后再把display修改为原来的值
    3. 如果需要创建多个DOM节点,可以使用DocumentFragment创建完后一次性的加入
  • 最好通过设置class的方式,避免通过style设置
  • 实现元素的动画,它的position属性应当设为fixed或absolute,这样不会影响其它元素的布局
  • 不要用table布局,用table的场合,可以设置table-layout为auto或fixed,这样可以让table一行一行的渲染
  • 避免使用css expression
  • 在HTML的标签中或在CSS中为所有图片指定宽度和高度,或它的块级父元素指定宽度和高度;指定与图片本身相一致的尺寸
  • 把外部样式表和内联样式块放在页面的中,确保样式表首先被下载和解析
  • 通过HTTP头信息或meta标签尽早指定正确的字符编码

其他优化点

  1. 能用css实现的不用img来做,能用css3实现,不用js来做(当然要综合考虑考虑兼容性和成本)
  2. 不要在线上使用@import 加载css
  3. 尽可能使用标准的CSS属性

进一步阅读

Rendering: repaint, reflow/relayout, restyle

Web页面Repaint和Reflow

如何减少浏览器repaint和reflow(上)

如何减少浏览器repaint和reflow(中)

如何减少浏览器repaint和reflow(下)

jQuery的使用优化

jQuery代码优化:选择符篇

jQuery代码优化:遍历篇

jQuery代码优化:基本事件篇

jQuery代码优化:事件委托篇

几个时间点

  1. DNS查询时间
  2. 建联时间
  3. 首包时间
  4. first paint时间
  5. 首屏时间
  6. 触发DomContentLoaded 时间
  7. 触发Load 时间

其他参考资料

浏览器的加载过程
从输入 URL 到页面加载完成的过程中都发生了什么事情?

浏览器系列

浏览器的工作原理:新式网络浏览器幕后揭秘

高性能浏览器网络(High Performance Browser Networking) 第一章
高性能浏览器网络(High Performance Browser Networking) 第二章

浏览器的渲染原理简介

网站优化经验(一) - 在浏览器键入url按回车后发生了啥

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注