从输入URL到浏览器呈现出精彩纷呈的页面究竟发生了什么呢?让我们一起去探索真相吧!

梳理主干流程

  1. 从浏览器接收url到开启网络请求线程(这一部分可以展开浏览器的机制以及进程与线程之间的关系)
  2. 开启网络线程到发出一个完整的http请求(这一部分涉及到dns查询,tcp/ip请求,五层因特网协议栈等知识)
  3. 从服务器接收到请求到对应后台接收到请求(这一部分可能涉及到负载均衡,安全拦截以及后台内部的处理等等)
  4. 后台和前台的http交互(这一部分包括http头部、响应码、报文结构、cookie等知识,可以提下静态资源的cookie优化,以及编码解码,如gzip压缩等)
  5. 单独拎出来的缓存问题,http的缓存(这部分包括http缓存头部,etag,catch-control等)
  6. 浏览器接收到http数据包后的解析流程(解析html-词法分析然后解析成dom树、解析css生成css规则树、合并成render树,然后layout、painting渲染、复合图层的合成、GPU绘制、外链资源的处理、loaded和domcontentloaded等)
  7. CSS的可视化格式模型(元素的渲染规则,如包含块,控制框,BFC,IFC等概念)
  8. JS引擎解析过程(JS的解释阶段,预处理阶段,执行阶段生成执行上下文,VO,作用域链、回收机制等等)
  9. 其它(可以拓展不同的知识模块,如跨域,web安全,hybrid模式等等内容)

从浏览器接收url到开启网络请求线程

这一部分展开的内容是:浏览器进程/线程模型,JS的运行机制

多进程的浏览器

浏览器是多进程的,有一个主控进程,以及每一个tab页面都会新开一个进程(某些情况下多个tab会合并进程)

进程可能包括主控进程,插件进程,GPU,tab页(浏览器内核)等等

  • Browser进程:浏览器的主进程(负责协调、主控),只有一个
  • 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
  • GPU进程:最多一个,用于3D绘制
  • 浏览器渲染进程(内核):默认每个Tab页面一个进程,互不影响,控制页面渲染,脚本执行,事件处理等(有时候会优化,如多个空白tab会合并成一个进程)
  • 如下图:

多线程的浏览器内核

每一个tab页面可以看作是浏览器内核进程,然后这个进程是多线程的,它有几大类子线程:

  • GUI线程
  • JS引擎线程
  • 事件触发线程
  • 定时器线程
  • 网络请求线程

可以看到,里面的JS引擎是内核进程中的一个线程,这也是为什么常说JS引擎是单线程的。

解析URL

输入URL后,会进行解析(URL的本质就是统一资源定位符)。

URL一般包括几大部分:

  • protocol,协议头,譬如有http,ftp等
  • host,主机域名或IP地址
  • port,端口号
  • path,目录路径
  • query,即查询参数
  • fragment,即#后的hash值,一般用来定位到某个位置

网络请求都是单独的线程

每次网络请求时都需要开辟单独的线程进行,譬如如果URL解析到http协议,就会新建一个网络线程去处理资源下载。

因此浏览器会根据解析出得协议,开辟一个网络线程,前往请求资源(这里,暂时理解为是浏览器内核开辟的,如有错误,后续修复)

更多

由于篇幅关系,这里就大概介绍一个主干流程,关于浏览器的进程机制,更多可以参考以前总结的一篇文章(因为内容实在过多,里面包括JS运行机制,进程线程的详解)。

从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理

开启网络线程到发出一个完整的http请求

这一部分主要内容包括:dns查询,tcp/ip请求构建,五层因特网协议栈等等。仍然是先梳理主干,有些详细的过程不展开(因为展开的话内容过多)。

DNS查询得到IP

如果输入的是域名,需要进行dns解析成IP,大致流程:

  • 如果浏览器有缓存,直接使用浏览器缓存,否则使用本机缓存,再没有的话就是用host
  • 如果本地没有,就向dns域名服务器查询(当然,中间可能还会经过路由,也有缓存等),查询到对应的IP
    注意,域名查询时有可能是经过了CDN调度器的(如果有cdn存储功能的话)。而且,需要知道dns解析是很耗时的,因此如果解析域名过多,会让首屏加载变得过慢,可以考虑dns-prefetch优化。这一块可以深入展开,具体请去网上搜索,这里就不占篇幅了(网上可以看到很详细的解答)。

tcp/ip请求

http的本质就是tcp/ip请求

需要了解3次握手规则建立连接以及断开连接时的四次挥手

tcp将http长报文划分为短报文,通过三次握手与服务端建立连接,进行可靠传输

三次握手的步骤:(抽象派)

1
2
3
客户端:hello,你是server么?
服务端:hello,我是server,你是client么
客户端:yes,我是client

建立连接成功后,接下来就正式传输数据

然后,待到断开连接时,需要进行四次挥手(因为是全双工的,所以需要四次挥手)

四次挥手的步骤:(抽象派)

1
2
3
4
主动方:我已经关闭了向你那边的主动通道了,只能被动接收了
被动方:收到通道关闭的信息
被动方:那我也告诉你,我这边向你的主动通道也关闭了
主动方:最后收到数据,之后双方无法通信

tcp/ip的并发限制

浏览器对同一域名下并发的tcp连接是有限制的(2-10个不等)。

而且在http1.0中往往一个资源下载就需要对应一个tcp/ip请求。

所以针对这个瓶颈,又出现了很多的资源优化方案

GET和POST的区别

get和post虽然本质都是tcp/ip,但两者除了在http层面外,在tcp/ip层面也有区别。

get会产生一个tcp数据包,post两个:

  • get请求时,浏览器会把headers和data一起发送出去,服务器响应200(返回数据)
  • post请求时,浏览器先发送headers,服务器响应100 continue,浏览器再发送data,服务器响应200(返回数据)。

再说一点,这里的区别是specification(规范)层面,而不是implementation(对规范的实现)。

五层因特网协议栈

其实这个概念挺难记全的,记不全没关系,但是要有一个整体概念

其实就是一个概念: 从客户端发出http请求到服务器接收,中间会经过一系列的流程。

简括就是:

从应用层的发送http请求,到传输层通过三次握手建立tcp/ip连接,再到网络层的ip寻址,再到数据链路层的封装成帧,最后到物理层的利用物理介质传输。

当然,服务端的接收就是反过来的步骤。

五层因特尔协议栈:

  1. 应用层(dns,http) DNS解析成IP并发送http请求
  2. 传输层(tcp,udp) 建立tcp连接(三次握手)
  3. 网络层(IP,ARP) IP寻址
  4. 数据链路层(PPP) 封装成帧
  5. 物理层(利用物理介质传输比特流) 物理传输(然后传输的时候通过双绞线,电磁波等各种介质)。