作为一个前端开发,最常见的运行环境应该是浏览器吧,为了更好的通过浏览器把优秀的产品带给用户,也为了更好的发展自己的前端职业之路,有必要了解从我们在浏览器地址栏输入网址到看到页面这期间浏览器是如何进行工作的,进而了解如何更好的优化实践,本篇主要围绕这两点展开阐述。前端页面渲染机制可谓是老生常谈,但又很有必要再谈的话题,于是还是决定写一篇,即是对知识的回顾总结,又能与大家分享,何乐而不为。网上相关类型的文章也很多,有兴趣的可以多学习一下。
浏览器
在介绍浏览器工作流程之前,先了解一下主流浏览器的基础结构,本文所介绍的浏览器主要为开源的Chrome,FireFox及部分开源的Safari,这也是目前市场占比最高的几大浏览器,以本人博客网站为例,可以大致看出各浏览器使用比例:
浏览器基础结构
浏览器基础结构主要包括如下7部分:
1.用户界面(User Interface):用户所看到及与之交互的功能组件,如地址栏,返回,前进按钮等;
2.浏览器引擎(Browser engine):负责控制和管理下一级的渲染引擎;
3.渲染引擎(Rendering engine):负责解析用户请求的内容(如HTML或XML,渲染引擎会解析HTML或XML,以及相关CSS,然后返回解析后的内容);
4.网络(Networking):负责处理网络相关的事务,如HTTP请求等;
5.UI后端(UI backend):负责绘制提示框等浏览器组件,其底层使用的是操作系统的用户接口;
6.JavaScript解释器(JavaScript interpreter):负责解析和执行JavaScript代码;
7.数据存储(Data storage):负责持久存储诸如cookie和缓存等应用数据。
浏览器内核
各大主要浏览器使用内核也是有差别的,大致可以分为以下几类:
Trident内核: IE
Webkit内核:Chrome,Safari
Gecko内核:FireFox
网络
当用户访问页面时,浏览器需要获取用户请求内容,这个过程主要涉及浏览器网络模块:
1.用户在地址栏输入域名,如baidu.com,DNS(Domain Name System,域名解析系统)服务器根据输入的域名查找对应IP,然后向该IP地址发起请求;
DNS
2.浏览器获得并解析服务器的返回内容(HTTP response);
3.浏览器加载HTML文件及文件内包含的外部引用文件及图片,多媒体等资源。
DNS预解析(DNS prefetch)
浏览器DNS解析大多时候较快,且会缓存常用域名的解析值,但是如果网站涉及多域名,在对每一个域名访问时都需要先解析出IP地址,而我们希望在跳转或者请求其他域名资源时尽量快,则可以开启域名预解析,浏览器会在空闲时提前解析声明需要预解析的域名,如:
多进程
我们通常说JavaScript执行是单进程的,但是浏览器网络部分通常是有几个平行进程同时开启,但是也会有限制,一般为2-6个。
渲染引擎及关键渲染路径(Critical Rendering Path)
渲染引擎所做的事是将请求内容展现给我们,默认支持HTML,XML和图片类型,对于其他诸如PDF等类型的内容则需要安装相应插件,但浏览器的展示工作流程基本是一样的。
通过网络模块加载到HTML文件后渲染引擎渲染流程如下,这也通常被称作关键渲染路径(Critical Rendering Path):
1.构建DOM树(DOM tree):从上到下解析HTML文档生成DOM节点树(DOM tree),也叫内容树(content tree);
2.构建CSSOM(CSS Object Model)树:加载解析样式生成CSSOM树;
3.执行JavaScript:加载并执行JavaScript代码(包括内联代码或外联JavaScript文件);
4.构建渲染树(render tree):根据DOM树和CSSOM树,生成渲染树(render tree);渲染树:按顺序展示在屏幕上的一系列矩形,这些矩形带有字体,颜色和尺寸等视觉属性。
5.布局(layout):根据渲染树将节点树的每一个节点布局在屏幕上的正确位置;
6.绘制(painting):遍历渲染树绘制所有节点,为每一个节点适用对应的样式,这一过程是通过UI后端模块完成;
为了更友好的用户体验,浏览器会尽可能快的展现内容,而不会等到文档所有内容到达才开始解析和构建/布局渲染树,而是每次处理一部分,并展现在屏幕上,这也是为什么我们经常可以看到页面加载的时候内容是从上到下一点一点展现的。
流程图
Webkit渲染引擎流程如下图:
Webkit渲染引擎流程
Gecko渲染引擎流程如下图:
Gecko渲染引擎流程
如上图,Webkit浏览器和Gecko浏览器渲染流程大致相同,不同的是:
1.Webkit浏览器中的渲染树(render tree),在Gecko浏览器中对应的则是框架树(frame tree),渲染对象(render object)对应的是框架(frame);
2.Webkit中的布局(Layout)过程,在Gecko中称为回流(Reflow),本质是一样的,后文会解释回流的另一层含义–重新布局;
3.Gecko中HTML和DOM树中间多了一层内容池(Content sink),可以理解成生成DOM元素的工厂。
单进程
不同于网络部分的多进程渲染引擎是单线程工作的,意味着渲染流程是一步一步渐进完成的。
解析文档(parser HTML)
在详细介绍浏览器渲染文档之前,先应该理解浏览器如何解析文档:解析文档的顺序,对于CSS和JavaScript如何处理等。
解析顺序
浏览器按从上到下的顺序扫描解析文档;
解析样式和脚本
脚本或许是由于通常会在JavaScript脚本中改变文档DOM结构,于是浏览器以同步方式解析,加载和执行脚本,浏览器在解析文档时,当解析到标签时,会解析其中的脚本(对于外链的JavaScript文件,需要先加载该文件内容,再进行解析),然后立即执行,这整个过程都会阻塞文档解析,直到脚本执行完才会继续解析文档。就是说由于脚本是同步加载和执行的,它会阻塞文档解析,这也解释了为什么现在通常建议将标签放在标签前面,而不是放在标签里。现在HTML5提供defer和async两个属性支持延迟和异步加载JavaScript文件,如:
关键渲染路径
关键渲染路径
关键渲染路径介绍
首先浏览器从上到下依次解析文档构建DOM树,如下:
浏览器从上到下依次解析文档构建DOM树
构建CSSOM树
CSSOM,即CSS对象模型(CSS Object Model),CSSOM树,与DOM树结构相似,只是另外为每一个节点关联了样式信息。
theme.css样式内容如下:
html, body {
width: 100%;
height: 100%;
background-col