# 现代浏览器进程
最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。
- 浏览器主进程。主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
- 渲染进程。核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
- GPU 进程。其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。
- 网络进程。主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
- 插件进程。主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
# 在浏览器中输入 URL 后发生了什么
- 用户输入 URL,浏览器会根据用户输入的信息判断是搜索还是网址,如果是搜索内容,就将搜索内容+默认搜索引擎合成新的 URL;如果用户输入的内容符合 URL 规则,浏览器就会根据 URL 协议,在这段内容上加上协议合成合法的 URL。
- 用户输入完内容,按下回车键,浏览器导航栏显示 loading 状态,但是页面还是呈现前一个页面,这是因为新页面的响应数据还没有获得。
- 浏览器进程浏览器构建请求行信息,会通过进程间通信(IPC)将 URL 请求发送给网络进程
GET /index.html HTTP1.1
。 - 网络进程获取到 URL,先去本地缓存中查找是否有缓存文件,如果有,则去检查缓存的有效期。在有效期内的缓存资源直接使用,称之为强缓存,拦截请求,直接 200 返回。通常来说,刷新页面会使用内存缓存,关闭后重新打开会使用磁盘缓存。超过有效期的,则携带缓存的资源标识向服务端发起请求,校验是否能继续使用,如果服务端告诉我们,可以继续使用本地存储,则返回 304,并且不携带数据;如果服务端告诉我们需要用更新的资源,则返回 200,并且携带更新后的资源和资源标识缓存到本地,方便下一次使用;否则,进入网络请求过程。
- 网络进程请求 DNS 返回域名对应的 IP 和端口号,如果之前 DNS 数据缓存服务缓存过当前域名信息,就会直接返回缓存信息;否则,发起请求获取根据域名解析出来的 IP 和端口号,如果没有端口号,http 默认 80,https 默认 443。如果是 https 请求,还需要建立 TLS 连接、协商加密密钥。
- Chrome 有个机制,同一个域名同时最多只能建立 6 个 TCP 连接,如果在同一个域名下同时有 10 个请求发生,那么其中 4 个请求会进入排队等待状态,直至进行中的请求完成。如果当前请求数量少于 6 个,会直接建立 TCP 连接。
- TCP 三次握手建立连接,http 请求加上 TCP 头部——包括源端口号、目的程序端口号和用于校验数据完整性的序号,向下传输。请求的基本组成是请求行+请求头+请求体,请求的基本组成是请求行+请求头+请求体。
- 网络层在数据包上加上 IP 头部——包括源 IP 地址和目的 IP 地址,继续向下传输到底层。
- 底层通过物理网络传输给目的服务器主机。
- 目的服务器主机网络层接收到数据包,解析出 IP 头部,识别出数据部分,将解开的数据包向上传输到传输层。
- 目的服务器主机传输层获取到数据包,解析出 TCP 头部,识别端口,将解开的数据包向上传输到应用层。
- 应用层 HTTP 解析请求头和请求体,如果需要重定向,HTTP 直接返回 HTTP 响应数据的状态 code 301 或者 302,同时在请求头的 Location 字段中附上重定向地址,浏览器会根据 code 和 Location 进行重定向操作;如果不是重定向,首先服务器会根据 请求头中的
If-None-Match
的值来判断请求的资源是否被更新,如果没有更新,就返回 304 状态码,相当于告诉浏览器之前的缓存还可以使用,就不返回新数据了;否则,返回新数据,200 的状态码,并且如果想要浏览器缓存数据的话,就在相应头中加入字段:Cache-Control:Max-age=2000
响应数据又顺着应用层——传输层——网络层——网络层——传输层——应用层的顺序返回到网络进程。 - 数据传输完成,TCP 四次挥手断开连接。如果,浏览器或者服务器在 HTTP 头部加上如下信息,TCP 就一直保持连接。保持 TCP 连接可以省下下次需要建立连接的时间,提示资源加载速度
Connection:Keep-Alive
。 - 网络进程将获取到的数据包进行解析,根据响应头中的
Content-type
来判断响应数据的类型,如果是字节流类型,就将该请求交给下载管理器,该导航流程结束,不再进行;如果是text/html
类型,就通知浏览器进程获取到文档准备渲染。 - 浏览器进程获取到通知,根据当前页面 B 是否是从页面 A 打开的并且和页面 A 是否是同一个站点(根域名和协议一样就被认为是同一个站点),如果满足上述条件,就复用之前网页的进程,否则,新创建一个单独的渲染进程。
- 浏览器会发出“提交文档”的消息给渲染进程,渲染进程收到消息后,会和网络进程建立传输数据的“管道”,文档数据传输完成后,渲染进程会返回“确认提交”的消息给浏览器进程。
- 浏览器收到“确认提交”的消息后,会更新浏览器的页面状态,包括了安全状态、地址栏的 URL、前进后退的历史状态,并更新 web 页面,此时的 web 页面是空白页。
- 渲染进程对文档进行页面解析和子资源加载,HTML 通过 HTM 解析器转成 DOM Tree(二叉树类似结构的东西),CSS 按照 CSS 规则和 CSS 解释器转成 CSSOM TREE,两个 tree 结合,形成 render tree(不包含 HTML 的具体元素和元素要画的具体位置),通过 Layout 可以计算出每个元素具体的宽高颜色位置,结合起来,开始绘制,最后显示在屏幕中新页面显示出来。
- 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。document
- 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。document.styleSheets
- 创建布局树,并计算元素的布局信息。
- 对布局树进行分层,并生成分层树。
- 为每个图层生成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
- 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。
- 具有明确定位属性的元素、定义透明属性的元素、使用 CSS 滤镜 filter 的元素、设置了 z-index 的元素等,都拥有层叠上下文属性。
- CSS 资源异步下载,下载和解析都不会阻塞构建 dom 树,可以放在 head 里
- JS 资源同步下载,下载和执行都会阻塞构建 dom 树,所以要加 defer、async 或者放在 body 底部,使得渲染能尽早开始。
- 在 JS 线程执行时,GUI 渲染线程没有办法去解析 HTML,这是因为 JS 可以操作 DOM,如果两者同时进行可能引起冲突。如果这时 JS 去修改了样式,那此时 CSS 的解析和 JS 的执行也没法同时进行了,会先等 CSS 解析完成,再去执行 JS,最后再去解析 HTML。从这个角度来看,CSS 有可能阻塞 HTML 的解析。
# DNS 查询过程
- 比如你有一个网站要上线,你在域名注册商那里申请了 abc.com。
- 那么你的域名 A 记录就保存在这个域名注册商的 DNS 服务器上,该 DNS 服务器称为权威域名服务器。
- 当客户端访问 abc.com 时,先查找浏览器 DNS 缓存,没有则查找操作系统 DNS 缓存,在这一阶段是操作系统 dnscache clinet 服务进行 DNS 缓存的(你在任务管理器里面可以看到一个 dns 客户端进程,就是这玩意实现缓存的)。
- 如果还是没有则查找/etc/hosts 文件中的域名记录。
- 然后依然没有的话则访问电脑上设置的 DNS 服务器 IP,比如三大营运商的 dns 服务器或者谷歌的 8.8.8.8,此时这一层的 DNS 服务器称为“野生 DNS 缓存服务器”,也就是非权威域名服务器。
- 如果还是没有则非权威域名服务器会去查找:根域名服务器->顶级域名服务器->二级域名服务器->权威域名服务器...,这样客户端就在权威域名服务器上找到了 abc.com 对应的 IP 了,这个 IP 可以是多个,每次客户端请求的时候域名服务器会根据负载均衡算法分配一个 IP 给你。
- 当 DNS 缓存失效了,则重新开始新一轮的域名请求。
总结如下:
- 浏览器缓存->操作系统 dnscache ->hosts 文件->非权威域名服务器->根域名服务器->顶级域名服务器->二级域名服务器->权威域名服务器。
- 其中非权威域名服务器还包括 LDNS(企业内网 DNS 服务器),三大营运商 DNS,谷歌公开的 DNS,微软公开的 DNS 等。
- 别忘了互联网上还有另外一个重要的角色 CDN,它也会在 DNS 的解析过程中“插上一脚”。DNS 解析可能会给出 CDN 服务器的 IP 地址,这样你拿到的就会是 CDN 服务器而不是目标网站的实际地址。
- 另外 DNS 请求有两种方式:递归查询和迭代查询,这方面大家可以网上了解一下。LDNS 往后面查询一般是递归查询,因为公司内网是有防火墙的,全部请求通过 LDNS 来递归查询然后把结果给内网用户。
- DNS 缓存比较简单,它主要就是在浏览器本地把对应的 IP 和域名关联起来。
# chrome 打开其他应用的链接样例
vscode://vscode.github-authentication/did-authenticate?windowid=4&code=54d033a63ff757ffec89&state=2874c601-0a26-4a06-a763-74213002e571