当在地址栏输入一个查询关键字的时候,地址栏会判断,输入的是需要搜索的关键字,还是请求的 URL 。如果是关键字,地址栏会结合浏览器所设置的搜索引擎来生成一个带输入关键字的 URL , 然后开始发起 URL
请求。如果浏览器判断输入的是合法的 URL ,那么浏览器也会进行相应的修正,比如为 lmssee.com 加上协议,合成完整的 URL : https://lmssee.com
然后开始请求。
当用户输入关键字并键入回车之后,这意味着当前页面即将要被替换成新的页面,不过在这个流程继续之前,浏览器还给了当前页面一次执行 beforeunload 事件的机会, beforeunload 事件允许页面在退出之前执行一些数据清理操作,还可以询问用户是否要离开当前页面,比如当前页面可能有未提交完成的表单等情况,因此用户可以通过 beforeunload 事件来取消导航,让浏览器不再执行任何后续工作。
此时,开始进入页面资源请求过程。浏览器会进行进程间通信 (IPC) 把 URL 请求发送到网络进程。当网络进程接收到 URL 请求时,首先网络进程会查找本地是否具有缓存。如果具备缓存资源,那么直接返回浏览器该缓存资源,否则直接进入网络请求流程。
请求的第一步会进入 DNS 解析,来获取域名的 IP 地址。域名解析需要访问一系列的域名解析服务器,来把该域名翻译成为 TCP/IP 协议的 IP 地址。
为提高 performance ,域名解析的过程中会设置多级的缓存,浏览器首先看一下自己的缓存里有没有,如果没有就向操作系统的缓存要,还没有就检查本机域名解析文件 hosts 。如果本地都找不到缓存,就会去顶级域名服务器“ com ”去查找,并且将该结果缓存。
当 Client 利用 IP 地址和服务器建立 TCP 连接后,浏览器会构建请求行、请求头等信息,并将该域名相关的 Cookie 等数据附加到请求头中,向服务器发送请求信息。 服务器接收到请求信息后,会根据请求信息生成响应数据(包括响应行、响应头和响应体等信息),并发给网络进程。等网络进程接收了响应行和响应头之后,就开始解析响应的内容了。
重定向
在接收到服务器返回的响应头后,网络进程开始解析响应头,如果发现返回的状态码是 301 或者 302 ,那么说明服务器需要浏览器重定向到其他 URL 。这时网络进程会从响应头的 Location 字段里面读取重定向的地址,然后再发起新的 HTTP 或者 HTTPS 请求,重头开始。如果响应行是 200 ,那么表示浏览器可以继续处理该请求。
应数据类型处理
通常 URL 请求的数据类型会包含 HTML 页面,或者下载数据类型。响应头中的 Content-type 会告知浏览器返回的数据类型。如 Content-type : text/html 表示返回数据 类型为 HTML 格式, Content-Type : application/octet-stream 表示返回数据类型为字节流类型,浏览器按照下载类型来处理。不同的 Content-Type 字段,浏览器后续处理流程会有所不同。如果是下载类型,那么浏览器会将请求任务提交给下载管理器,同时关闭导航流程。如果是 HTML 浏览器的导航流程还会继续,并通知渲染进程开始进行渲染页面。
默认情况下, Chrome 会为每个页面分配一个渲染进程,也就是说,每打开一个新页面就会配套创建一个新的渲染进程。但是,也有一些例外,在某些情况下,浏览器会让多个页面直接运行在同一个渲染进程中。
当从新的页面打开另外一个页面,并且这些页面属于同一个站点 (same-site) 的话 , 那么新页面会复用父页面的渲染进程 (process-per-site-instance) 。
渲染进程准备好之后,它就会通知浏览器进程,可以替换当前旧的文档了,具体地讲,需要经过下列几个步骤 :
文档被提交,渲染进程便开始页面解析和子资源加载了。该过程主要涉及 HTML,CSS,JavaScript 如何生成页面。从解析 *.html 文件,生成 DOM, CssDOM, Render Tree, 再到计算布局 (layout) ,绘制 (paint) ,合成页面 (composite layers), 每个过程都涉及到优化问题。开发者应该注重用户体验,防止页面卡顿,使用 JavaScript 优化动画流程,优化样式表等来防止强制同步布局等。
生成 Render Tree
然后根据 CSS 的样式规则,我们依次得到各 Node 与对应的 CSS 样式结合,再生成 Render Tree 。其中 Render Tree 与 DOM tree 非常类似,不同的是 Render tree
没有 head 也不含任何脚本。如果 CSS 样式中设置了 {display: none; }
属性的话,该 node 也会从 Render tree 中移掉,对于一些伪元素,例如添加了
h1:after {
content: 'this will be visible';
}
属性, Render tree 会添加该 node, 但 DOM 并不会包含这个 node 。需要注意的是,只有实际显示在网页上的元素才会进入 Render tree 。
计算布局
当浏览器知道哪个规则适用于哪个元素后,就会开始进入布局计算阶段。其中具体样式适用元素的规则需要根据 CSS 的继承规则和层叠规则计算。我们可以通过盒模型,排版等计算每个节点坐标,大小,得到页面的布局。这一过程比较复杂,该计算过程也称为回流 (reflow) 。
光栅化
得到计算的布局之后,便可以矢量光栅化到图形 (vector 2 raster) ,矢量的栅格化到图形 render tree 通过计算边框、绘制文本、绘制阴影、白线、绘制位图最终形成的展示内容。
浏览器会根据需要创建多个图层,单独绘制这些图层并合成层。
对于绘制和合成页面的中间过程,还会涉及到跨进程操作。通常,绘制过程中,都是在一系列的网格图块( tiles )中实现的。图层会将其本身以及图块上传到 GPU 中进行栅格化加速生成。使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。 GPU 操作是运行在 GPU 进程中,如果栅格化操作使用了 GPU ,那么最终生成位图的操作是在 GPU 中完成的。
首次载入网站进行访问时,浏览器和服务器的完整交互步骤如下。
https://lmssee.cn/about
首先访问网站首页完毕后,浏览器将清单中的列表文件完全载入缓存。如果再次打开浏览器访问该网站,并且 manifest 文件中的内容没有被修改过,它们的交互过程如下 。
https://lmssee.cn/about
如果再次通过浏览器访问网站页面,并且 manifest 文件的内容已经被修改过了,它们的交互过程如下
https://lmssee.cn/about
即使资源文件被修改过了,任何之前载入的资源都不会发生变化。例如,图片不会改变,旧的 JavaScript 函数也不会改变。也就是说,更新过后的本地缓存中的内容还不能被使用,只有重新打开这个页面的时候才会使用更新过的资源文件