34

浏览器工作原理

写在前面

本人对浏览器的工作原理的理解尚浅,如有错误欢迎各位大佬指正。

本文章回答了那些问题

  1. 浏览器如何渲染一个页面

  2. 浏览器有哪些线程,线程之间如何工作的

为什么要学习这些问题

  1. 了解浏览器渲染原理可以帮助我们优化html、css、js的组织,优化渲染性能

  2. 了解浏览器进程可以帮助我们深入了解异步编程

浏览器渲染原理

浏览器首先下载html、css、js。 接着解析生成dom tree、rule tree和rendering tree。 再通过layout后渲染页面。

下载

浏览器打开页面之后,会根据页面URL向服务器发送一个请求,服务器响应页面的HTML。
(HTML解析过程中遇到插入的css、和js会同时发起请求资源。)

解析

html/svg 解析生成 dom tree,css 解析生成 css rule tree, 这两者结合生成rendering(render) tree。

渲染树包含多个带有视觉属性(颜色、尺寸等)的矩形, 这些矩形的排列顺序就是它们在屏幕上的显示顺序

解析过程中遇到js标签会下载解析执行

解析的过程是词法分析和语法分析

layout

渲染树构建完成之后进入layout阶段

layout是指计算每个DOM元素最终在屏幕上显示的大小和位置。 遍历顺序为从左至右,从上到下

由于web页面的元素布局是相对的, 所以任意元素的位置发生变化,都会引起其他元素位置的变化,这就是reflow

paint

渲染引擎会遍历渲染树,由用户界面后端层将每个节点绘制出来

按照合理的顺序合并图层然后显示到屏幕上。

浏览器刷新的频率大概是60次/秒, 也就是说刷新一次大概时间为16ms

如果浏览器对每一帧的渲染工作超过了这个时间, 页面的渲染就会出现卡顿的现象。

以上过程是渐进的,并不一定严格按照顺序执行的,为了更快将内容呈现在不屏幕中, 不会等到HTML全部解析完成之后才开始构建渲染树和layout,它会在不断接收和处理其他网络资源的同时,就开始部分内容的解析和渲染

渲染完成之后会触发 ready事件

什么情况下会引起 reflow repaint

当render tree (元素尺寸) 发生变化时则会重新layout 则会因此reflow

浏览器内核

浏览组成

用户界面

浏览器内核: 浏览器引擎(查询操作渲染引擎的接口)、渲染引擎、js引擎、网络(http请求)

数据存储

js引擎 (IE9+: Chakra firefox:monkey chrome:v8)

渲染引擎(firefox:gecko、chrome/safari:webkit)

所以大部分浏览器至少有三个线程:

JS引擎线程、GUI渲染线程、浏览器事件触发线程

除此之外还会有 http请求线程等、计时器线程、EventLoop轮询的处理线程等。

javascript引擎

js引擎是基于事件驱动的, 采用的是单线程运行机制。

因为JS可以操作DOM元素, 从而影响到GUI的渲染结果, 因此JS引擎线程和GUI渲染线程是互斥的。 也就是说
JS引擎处于运行状态时,GUI渲染线程将处于冻结状态。

javascript的单线程

javascript引擎负责解释和执行javascript代码的线程只有一个,称为主线程。js还有其他的线程称为工作线程。

主线程上只执行同步任务。

Web Worker

H5提出了Web Worker标准, 允许js创建多个线程, 但是完全受父线程控制,且不可以操作DOM

工作进程

浏览器还有还有其他的线程,例如:

处理 ajax 的线程,dom事件线程、定时器线程、读写文件的线程等。这些被称为工作进程

这些线程可能存在于js引擎之中或者之外, 称为工作线程
工作线程的任务完成之后, 会推入到一个任务队列(task queue)

JavaScrpt 的异步编程

js引擎只执行同步任务, 异步任务会有工作线程来执行。

异步过程

当需要进行异步操作(定时器、ajax请求、dom事件注册等), 主线程会发一个异步任务的请求, 相应的工作线程接受请求; 当工作线程完成工作之后, 通知主线程;主线程接收到通知之后, 会执行一定的操作(回调函数)。

事件循环

主线程和工作线程之间的通知机制叫做事件循环。

调用栈 (call stack): 主线程执行时生成的调用栈

任务队列 (task queue): 工作线程完成任务后会把消息推到一个任务队列, 消息就是注册时的回调函数

当调用栈为空时, 主线程会从任务队列里取一条消息并放入当前的调用栈当中执行, 主线程会一直重复这个动作直到消息队列为空。 这个过程就叫做事件循环 (event-loop)。

渲染线程和js线程的互斥

渲染线程和js线程是互斥的, 在js引擎执行时,渲染线程会被挂起。

为什么会阻塞

js在浏览器中需要被下载、解释、执行这三部。 html中的script标签是阻塞的, 也就是说顺序下载、解释、执行。

浏览器会在js执行后决定当前文档是否需要进行重新渲染或者重排。
js引擎线程和UI线程是互斥的, 所以js执行时会阻塞页面的渲染。

下载虽然是异步的, 但是执行还是同步的。 先出现的SCRIPT标签一定是先执行。 即使它是最后一个下载完成。
js执行中终端浏览器html解析


小木头
162 声望7 粉丝