当我们打开一个网站我们期待什么?
1.希望页面内容能尽快加载完,不要让我一直等
2.网站交互是流畅的
3.能刷到感兴趣的内容
进程和线程
进程:进程是计算机中程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。
线程:线程是操作系统能够进行运算调度的最小单位。
进程=火车,线程=车厢
- 线程在进程下行进 (单纯的车厢无法运行)
- 一个进程可以包含多个线程 (一辆火车可以包含多个车厢)
- 不同进程间数据很难共享 (一辆火车上的乘客很难换乘到另外一辆火车,比如站点换乘)
- 同一进程下不同线程间数据很容易共享 (A车厢很容易换乘到B车厢)
- 进程间不会相互影响,一个线程挂掉将导致整个进程挂掉
当一个程序启动时,一个进程就被创建了。应用程序可能会创建一些线程帮助它完成某些工作。操作系统会划分出一部分
内存给这个进程,当前应用程序的所有状态都将保存在这个私有的内存空间中。
浏览器是多进程
以Chrome 为例,主要的进程有4个
1.浏览器进程(Browser Process)负责浏览器的Tab的前进、后退、地址栏、书签栏的工作和处理浏览器一些不可见的底层操作,比如网络请求和文件访问。
2.渲染进程(Renderer Process) 负责一个Tab内的显示相关的工作,也称渲染引擎。
3.插件进程(Plugin Process)负责控制网页使用到的插件
4.GPU进程 (GPU Process) 负责处理整个应用程序的GPU任务
浏览器渲染进程
- GUI渲染线程
- 解析HTML,CSS,构建DOM树、构建render树,布局和绘制等
- 界面重绘(Repaint)或回流(reflow)
- JS引擎线程
- 处理JavaScript程序
- JS引擎一直等待着任务队列中任务的到来,然后加以处理
- 事件触发线程
- 当JS引擎执行如setTimeOut代码块时,或者是其他的如网络异步请求、鼠标点击等时,会将对应任务添加到事件线程中。当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理的事件队列中,等待JS引擎空闲时处理。
- 定时器线程
- setInterval与setTimeout所在线程。计时完毕后,将对应事件添加到事件队列中,等待JS引擎空闲时处理。
- 异步网络请求线程
- 处理网络请求,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。等待JS引擎空闲时处理。
GUI渲染线程和JS引擎线程是互斥的,当JS引擎线程执行时,GUI渲染线程会被挂起。这是因为JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JS线程和UI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。
导航
1.dns 查找
2.tcp 三次握手
3.服务端响应
1 | <!doctype HTML> |
解析
一旦浏览器收到数据的第一块,它就可以开始解析收到的信息。“推测性解析”,“解析”是浏览器将通过网络接收的数据转换为DOM和CSSOM的步骤,通过渲染器把DOM和CSSOM在屏幕上绘制成页面。
构建DOM树
子资源加载
除了HTML文件,网站通常还会使用到一些诸如图片,CSS样式以及JavaScript脚本等子资源。这些文件会从缓存或者网络上获取。
1.当遇到script标签时,会阻塞解析html, 添加async或者defer 属性可以避免阻塞解析html
script 脚本加载和执行的区别(红线代表Javascript 执行,绿线代表HTML解析, 蓝色线代表Javascript加载)
defer脚本会在DOMContentLoaded事件前执行完,有序
async脚本会在load事件前完成,无序
构建CSSOM树
构建CSSOM并不需要等待所有DOM都构建完毕。而是在解析HTML构建DOM时,若遇见CSS会立刻构建CSSOM。即DOM 和 CSSOM 是并行构建的。
构建CSSOM和构建DOM是可以同时进行的。不过进入下一个构建渲染树阶段必须要等待CSSOM构建完毕后才能进行。因为CSS的每个属性都可以改变CSSOM,所以会存在这样一个问题:假设前面几个字节的CSS将字体大小设置为16px,后面又将字体大小设置为14px,那么如果不把整个CSSOM构建完整,最终得到的CSSOM其实是不准确的。所以必须等CSSOM构建完毕才能进入到下一个阶段,哪怕DOM已经构建完,它也得等CSSOM,然后才能进入下一个阶段。
所以,CSSOM 会阻塞渲染,只有当 CSSOM 构建完毕后才会进入下一个阶段构建渲染树。
渲染
渲染步骤包括样式、布局、绘制,在某些情况下还包括合成。在解析步骤中创建的CSSOM树和DOM树组合成一个Render树,然后用于计算每个可见元素的布局,然后将其绘制到屏幕上。
样式 Style
第三步是将DOM和CSSOM组合成一个Render树,计算样式树或渲染树从DOM树的根开始构建,遍历每个可见节点。
布局 Layout
渲染树上运行布局以计算每个节点的几何体。
绘画 Paint
在绘制或光栅化阶段,浏览器将在布局阶段计算的每个框转换为屏幕上的实际像素。绘画包括将元素的每个可视部分绘制到屏幕上,包括文本、颜色、边框、阴影和替换的元素(如按钮和图像)。
合成
合成是将页面分成若干层,然后分别对他们进行光栅化,最后在一个单独的线程(合成线程)里面合成一个页面的技术。
重绘
当 render tree 中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如 background-color,这个过程叫做重绘(repaint) 重绘时机有
- 当一个元素的外观的可见性 visibility 发生改变的时候,但是不影响布局
- 回流会引起重绘
回流
当 render tree 中的一部分(或全部)因为元素的尺寸、布局、显示/隐藏等改变而需要重新构建,这个过程称作回流(reflow)。页面第一次加载的时候,至少发生一次回流。 回流时机有
- 页面渲染初始化。
- 调整窗口大小。
- 改变字体,比如修改网页默认字体。
- 增加或者移除样式表。
- 内容变化,比如文本改变或者图片大小改变而引起的计算值宽度和高度改变。
- 激活 CSS 伪类,比如 :hover
- 操作 class 属性。
- 脚本操作 DOM,增加删除或者修改 DOM
- 节点,元素尺寸改变——边距、填充、边框、宽度和高度。
- 计算 offsetWidth 和 offsetHeight 属性。
- 设置 style 属性的值。
在回流的时候,浏览器会使 render tree 中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。因此回流必将引起重绘,而重绘不一定会引起回流。
Reflow 的成本比 Repaint 高得多的多。DOM Tree 里的每个结点都会有 reflow 方法,一个结点的 reflow 很有可能导致子结点,甚至父点以及同级结点的 reflow。
load和DOMContentLoaded
- 当load事件触发时,页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了。
- 当 DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash。