这是我参与更文挑战的第 6 天,活动详情查看: 更文挑战
大部分前端工作都是浏览器相关的,对于每个前端工程师每天都为如何解决那些浏览器间的兼容性而困扰。为了解决这些困扰,觉得有必要进一步了解一下浏览器内部的机制,也就是如何将我们的 html css 渲染到界面上的知识。我们这里就以当下市场份额最大 chrome 浏览器为例来介绍,虽然浏览器种类众多但是大家基本结构都类似如下图
- 用户界面(User Interface): 提供用户与浏览器引擎交互的方法。其中包括:地址栏、向前/退后按钮、书签菜单等等。浏览器除了渲染请求页面的窗口外的所有地方都属于用户界面
- 浏览器引擎(Browser Engine): 协调用户界面和浏览器引擎,在他们之间传输数据和指令
- 渲染引擎(Rendering Engine): 解析 html 和 css 生成渲染树,将合并后,将渲染树绘制到屏幕上呈现给用户
浏览器内核
浏览器本身是运行在操作系统上一个应用程序,早期浏览器是一个单进程的应用程序,包含多个线程来完成不同任务,例如 page 线程负责渲染界面,JavaScript 线程负责运行 js 代码等等。
现在的浏览器都是多进程结构,从而避免某一个进程出现问题不会影响应用程序退出。同时因为所有页面都运行在一个进程下,也就是浏览器之间是可以共享数据的,javascript 线程可以随意访问进程中所有数据。而且一个进程要处理太多任务可能导致不流畅,不能提供良好的用户体验。
- 不安全
- 不稳定
- 不流畅
就以上问题,现在浏览器都采用多进程的结构
- 浏览器进程(Browser Process): 负责控 chrome 浏览器除了标签页所有用户界面、例如标题栏、地址栏以及后退按钮,以及负责与其他浏览器之间的协调工作。
- 网络进程顾名思义用于发起网络请求
- GPU 进程负责网络的渲染
- 插件进程负责管理和控制浏览器标签插件,这里插件指的不是 chrome 扩展
- 渲染进程,浏览器在默认情况下会为每个标签页创建一个进程
如何渲染页面到浏览器页面上
当你输入一个网站时,浏览器就会发起网络请求加载页面,如果你输入是一个关键字,浏览器就会启动默认搜索引擎来对关键字进行搜索。
首先将 HTML 和 CSS 解析为一定的数据结构(渲染对象),然后再将渲染对象按一定规则(就是将 style 树 合并到 dom 树上)形成渲染树,接下来对生成渲染树各个节点进行布局(也就是按 dom 节点的位置信息进行排版),最后读取渲染树,绘制成图片放到屏幕上。
HTML 的解析
首先浏览器是以超强纠错形式来解析 html,即便 html 有错误,浏览器也相对智能地将 html 进行解析,所以说对 html 的解析不是一般简单解析工作,html 解析要相对复杂。解析 html 会得到一个 DOM 树,类似写一篇文章的结构,根据 W3C 组织定义标准来得到一个描述页面结构的树。
接下来就是构建一颗渲染树,渲染树中不会包含像 head 标签或 display:none 标签对应的元素的不会包含在渲染树种,但是这些元素会存在于 DOM 树中。
对渲染树进行布局(layout),主要对元素进行定位、大小以及确定是否换行
在解析过程是可以被 js 或其他原因所中断的。例如网络不畅通,link 和 style 标签加载,相对高级的浏览器为提高效率,提供一定进程进行预解析,也可以加载图这样耗时的工作可以另一个进程中完成。
Parser 和 Tokenizer 其实只是把无意义的字符流变得有某种意义而已。Parse 这个词其实可以用在很多的地方,比如说只要你能在一个字符流中标识出所有的字符 a,你就在做 Tokenize 和 Parse。你可以看得出,Parse 和 Tokenize 有多难实际是针对编程的人的目的来说的。