了解浏览器工作原理对前端性能优化有很大帮助。从浏览器地址栏输入一个url到最终web页面的呈现经历了:http协议解析——构建Dom树——为Dom树添加css样式属性——排版布局——渲染合成绘制
Http协议
http协议是基于tcp的纯文本协议,客户端发送请求,服务端给予响应。请求是一段约定好的文本,分为request line,head,body三部分。响应分为response line,head,body三部分。
Request line包含了请求的方法,协议版本等
请求头是主要包含一些约定的属性,如它所支持的数据类型,支持的字符集,告诉服务器缓存数据时间,告诉服务态器它的语言环境等。
Response line包含了返回的状态码,状态码表示本次请求是否成功完成,我们可以根据状态码来定位问题。其他还包括状态文本,协议版本等。
响应头包含了服务器告诉浏览器的一些信息,比如服务器型号,告诉浏览器语言环境,报文类型,要不要缓存,数据长度,数据类型,时间,要不要定时刷新等。
响应体就是服务端返回的html代码或者图片了。
- 请求的方法
- get,请求参数会追加的url,对于一些重要信息不适合,并且URL有长度限制
- Post,常用在表单提交,文件上传等,数据包含在请求体中,请求体的大小取决于服务端的接受能力。
- Head,类似get只不过返回的响应中不包含响应体。
- 还有其他几种,delete,options,connect等。
- 响应的状态码
常用的响应状态码有:
- 200表示服务端成功返回
- 3xx表示请求目标有变化,客户端需要重新处理,如301 302重定向,临时或永久跳转
- 4xx表示客户端请求错误,如404请求页面不存在,403客户端无权限
- 5xx表示服务端请求错误
构建Dom树
上一阶段浏览器从响应体中拿到了html代码,浏览器开始解析html并生成dom树。通过栈来构建Dom树,栈顶元素就是当前节点,遇到属性就为当前节点添加属性,遇到文本节点就合并到当前文本节点或者作为子节点,遇到注释节点就添加到为当前节点的子节点,遇到"<"就入栈一个节点,当前节点就是其父节点,遇到“<”就出栈一个节点。
为Dom添加css样式
我们常说css选择器,其实并不是说我们dom树构建好之后,才去拿css样式去选择dom上的节点来增加css属性,而是在构建dom的过程中即开始“匹配”css属性,这是一个“流水线”式的过程。由上一步我们知道浏览器使用一个栈来构建dom树,并且都是先入栈父节点,后入栈子节点的,这就决定了css样式的定义也必须是先父后子,如此才能在构建dom树的进程中一旦匹配到正确的css样式就给该节点添加css属性到dom节点上。所以初学者在熟悉css知识的时候都是学习css的选择器,如“ ”(空格——后代选择器,子节点和子节点的后代),“+”(直接后继选择器,下一个相邻节点),“>”(子代选择器),"~"(后继选择器,所有相邻节点),“,”(逗号——表示"或"的关系)。
排版布局
这一步的主要工作是确定每个元素(图片,文字,图形,表格)的位置,确定每个元素位置的过程就是排版。在浏览器上一步浏览器已经构建了一个包含css属性的dom树,每个节点都有各自节点的尺寸。
- 正常流布局
首先浏览器正常情况下是使用正常流布局,即从左到右,从上到下这样的顺序。节点分为块级元素(block),行内元素(inline)。块级元素独占一行,具有盒模型的结构,即具有盒模型的宽度,高度,margin,padding等。行内元素在一行内进行顺次布局,从左到右,一行不够就换行显示,行内元素又分成两种即普通行内元素(inline)和行内块元素(inline-block)。inline元素不能设置宽高等信息,只能按照固有的文字或者图片的宽度来布局。inline-block即具备了行内布局的特性,又具有块级元素的特性。我们都知道div是块元素,a是行内元素,其实每种标签之所以会有区别,无非是浏览器给他们默认的配备了块元素和行元素的区别,我们可以对任意标签修改其display属性,来修改其原本的布局属性,比如我们经常做的为a标签设置成块元素,这样链接就具备了宽高的特性。
- 绝对定位
绝对定位脱离了正常的流布局,如position:absolute,通过top,left等位置信息来定位(参考上一个position非static的元素),position:relative,以本身在布局流原本应该所在的位置来相对定位。position:fixed,相对于浏览器窗口的原点位置保持不变,如此滚动网页,元素会保持不动,除非拖动浏览器位置。
- float
浮动也是脱离正常的流布局,只不过浏览器对float的处理是先排入正常流再移动到当前行的排版宽度的最左或者最右(主轴的最前和最后)。
当一个元素浮动后,它会被移出正常的文档流, 然后向左或向右平移,一直平移到碰到所处的容器的边框,或者碰到另外一个浮动元素。
元素浮动后会在主轴和交叉轴方向上占据一部分空间,其他元素会在元素脱离流后重新在该行布局,如一些文字会出现环绕效果。在数行之内,主轴方向上的排版宽度会受影响,直到交叉轴方向上超过了浮动元素的高度,排版宽度才恢复。
- flex
flex属性将每一行排版后的剩余空间平均分配给主轴方向的宽度和高度属性。
渲染、合成、绘制
上一步我们获得了元素位置信息和大小信息。最后一步就是根据每个元素的样式信息、大小信息在内存中渲染出位图,并绘制到正确的位置。值得一提的是这种渲染合成绘制的过程也是一个和上面几步组成流水线模式,所以我们经常见到网页的渲染有时候是一个区域一个区域的逐渐显示。
渲染的过程就是变成位图的过程。
合成是把一部分不经常更新的元素的位图合成到一起,以减少渲染成位图的次数,对于那些用户可能操作的dom元素则不进行合成,这种合成的机制完全由浏览器来决定。
绘制就是把位图交由GPU图形处理器呈现到显示器上。