主干流程
- 从浏览器接收 url 到开启网络请求进程
- 开启网络进程到发出一个完整的 http 请求
- 从服务器接收到请求到对应后台接收到请求
- 后台和前台的 http 交互
- 单独拎出来的缓存问题,http 的缓存
- 浏览器接收到 http 数据包后的解析流程
1. 从浏览器接收 url 到开启网络请求进程
多进程的浏览器
- 浏览器进程:主要负责界面显示、用户交互、子进程管理,同时提供存储等功能
- GPU进程:3D 绘制
- 网络进程:页面的网络资源加载
- 插件进程:因插件容易崩溃,所以用插件进程来隔离
- 渲染进程:每个 Tab 标签就是一个渲染进程
在浏览器中打开一个网页相当于新起了一个进程(进程内有自己的多线程)
多线程的浏览器内核
每一个tab页面可以看作是浏览器内核进程,然后这个进程是多线程的
在解析完 URL 后,浏览器进程会通过进程间通信(IPC)把 URL 请求发送到网络进程,网络进程接收到 URL 请求后,会在这里发起真正的 URL 请求流程
2. 开启网络进程到发出一个完整的 http 请求
五层因特网协议栈
从应用层的发送http请求,到传输层通过三次握手建立tcp/ip连接,再到网络层的ip寻址,再到数据链路层的封装成帧,最后到物理层的利用物理介质传输。
- 应用层(dns, http)DNS 解析成 IP 并发送 http 请求
- 传输层(tcp, udp)建立 tcp 连接(三次握手)
- 网络层(IP, ARP)IP 寻址
- 数据链路层(PPP)封装成帧
- 物理层(利用物理介质传输比特流)物理传输(然后传输的时候通过双绞线,电磁波等各种介质)
DNS 解析
先拿dns缓存,没有缓存 -> 本地dns服务器 -> 根 dns 服务器 -> 顶级 dns 服务器 -> 权威 dns 服务器 -> GSLB3. 从服务器接收到请求到对应后台接收到请求
负载均衡
用户发起的请求都指向调度服务器(反向代理服务器,譬如安装了 nginx 控制负载均衡),然后调度服务器根据实际的调度算法,分配不同的请求给对应集群中的服务器执行,然后调度器等待实际服务器的 HTTP 响应,并将它反馈给用户
4. 后台和前台的 http 交互
http 报文结构
- HTTP 请求数据格式
- 服务器响应的数据格式
状态码
cookie 及其优化
常用来进行身份校验
- Expires:过期时间(绝对时间点)
- Max-Age:相对时间(优先级较高)
- Domain”和“Path”指定了 Cookie 所属的域名和路径
- HttpOnly:此 Cookie 只能通过浏览器 HTTP 协议传输,禁止其他方式访问,浏览器的 JS 引擎就会禁用 document.cookie 等一切相关的 API(XSS跨站脚本攻击)
- SameSite:防范“跨站请求伪造”(XSRF)攻击,设置成“SameSite=Strict”可以严格限定 Cookie 不能随着跳转链接跨站发送,而“SameSite=Lax”则略宽松一点,允许 GET/HEAD 等安全方法,但禁止 POST 跨站发送。
Secure:表示这个 Cookie 仅能用 HTTPS 协议加密传输,明文的 HTTP 协议会禁止发送
连接管理
短连接(short-lived connections)
- 长连接(persistent connections)
Connection: keep-alive/close
5. http 的缓存(Cache)
基于 HTTP“请求 - 应答”模式的特点,可以大致分为客户端缓存和服务器端缓存
服务器的缓存控制
- 浏览器发现缓存无数据,于是发送请求,向服务器获取资源
- 服务器响应请求,返回资源,同时标记资源的有效期
- 浏览器缓存资源,等待下次重用
- max-age:时间的计算起点是响应报文的创建时刻(即 Date 字段,也就是离开服务器的时刻),而不是客户端收到报文的时刻,也就是说包含了在链路传输过程中所有节点所停留的时间。
- no-store:不允许缓存
- no-cache:可以缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本
- must-revalidate:如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证
客户端的缓存控制
Cache-Control: max-age=0/no-cache:不使用缓存,直接向服务器发请求
sessionStorage
页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。
- 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,通过location.href、window.open、或者通过带target=”_blank”的a标签打开新标签,之前的sessionStorage还在,但从此之后,新窗口(或标签)的sessionStorage的增删改和旧窗口已经没有关系了
- 打开多个相同的URL的Tabs页面,会创建各自的sessionStorage。
关闭对应浏览器窗口(Window)/ tab,会清除对应的sessionStorage。
强缓存与协商缓存
强缓存时,浏览器如果判断本地缓存未过期,就直接使用,无需发起 http 请求
- 协商缓存(304)时,浏览器会向服务器发起 http 请求,然后服务器告诉浏览器文件未改变,让浏览器使用本地缓存
6. 解析页面流程
流程简述
- 构建 DOM 树
- 样式计算
- 布局
- 分层
- 图层绘制
- 光栅化
- 合成绘制
构建 DOM 树
- 输入:HTML 文档;
- 处理:HTML 解析器解析;
- 输出:DOM 数据解构。
样式计算
- 输入:CSS 文本
- 处理:属性值标准化,每个节点具体样式(继承、层叠)
- 输出:styleSheets(CSSOM)
布局
- DOM & CSSOM 合并成渲染树
- 布局树(DOM 树中的可见元素)
- 布局计算
分层
- 特定节点生成专用图层,生成一棵图层树(层叠上下文、Clip,类似 PhotoShop 里的图层);
- 拥有层叠上下文属性(明确定位属性、透明属性、CSS 滤镜、z-index 等)的元素会创建单独图层;
- 没有图层的 DOM 节点属于父节点图层;
- 需要剪裁的地方也会创建图层。
图层绘制
- 把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表
绘制列表只是用来记录绘制顺序和绘制指令的列表
光栅化(栅格化)raster
- 当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给渲染引擎中的合成线程
- 在光栅化线程池中,将视口附近的图块优先生成位图(栅格化执行该操作);
- 快速栅格化:GPU 加速,生成位图(GPU 进程)。
合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的
合成绘制
- 绘制图块命令——DrawQuad,提交给浏览器进程;
- 浏览器进程的 viz 组件,根据DrawQuad命令,绘制在屏幕上。
相关概念
重排(Layout,也称为Reflow,即回流)
更新了元素的几何属性
重绘(repaint)
更新元素的绘制属性
直接合成阶段
使用了 CSS 的 transform 来实现动画效果,这可以避开重排和重绘阶段
CSS 动画比 JS 高效的原因
JS 执行动画会占用渲染主线程,而 CSS 操作动画,如果帧的生成方式是合成,那么直接在合成线程操作不会引起渲染主线程阻塞