浏览器相关原理(面试题)详细总结一

1. Chrome 打开一个页面须要启动多少进程?分别有哪些进程?

浏览器从关闭状态进行启动,而后新开 1 个页面至少须要 1 个网络进程、1 个浏览器进程、1 个 GPU 进程以及 1 个渲染进程,共 4 个进程;后续再新开标签页,浏览器、网络进程、GPU进程是共享的,不会从新启动,若是2个页面属于同一站点的话,而且从a页面中打开的b页面,那么他们也会共用一个渲染进程,不然新开一个渲染进程。前端

最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程。git

  • 浏览器进程:主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
  • 渲染进程:核心任务是将 HTML、CSS 和 JavaScript 转换为用户能够与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认状况下,Chrome 会为每一个 Tab 标签建立一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
  • GPU 进程:其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器广泛的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。
  • 网络进程:主要负责页面的网络资源加载,以前是做为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
  • 插件进程:主要是负责插件的运行,因插件易崩溃,因此须要经过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面形成影响。

该题答案引用 《浏览器工做原理与实践》里的内容github

2. 如何保证页面文件能被完整送达浏览器?

互联网中的数据是经过数据包来传输的。数据包要在互联网上进行传输,就要符合网际协议(IP),互联网上不一样的在线设备都有惟一的地址,地址只是一个数字,只要知道这个具体的地址,就能够往这里发送信息。浏览器

若是要想把一个数据包从主机 A 发送给主机 B,那么在传输以前,数据包上会被附加上主机 B 的 IP 地址信息,这样在传输过程当中才能正确寻址。额外地,数据包上还会附加上主机 A 自己的 IP 地址,有了这些信息主机 B 才能够回复信息给主机 A。这些附加的信息会被装进一个叫 IP 头的数据结构里。IP 头是 IP 数据包开头的信息,包含 IP 版本、源 IP 地址、目标 IP 地址、生存时间等信息。缓存

IP 是很是底层的协议,只负责把数据包传送到对方电脑,可是对方电脑并不知道把数据包交给哪一个程序,是交给浏览器仍是交给王者荣耀?所以,须要基于 IP 之上开发能和应用打交道的协议,最多见的是用户数据包协议(User Datagram Protocol),简称UDP传输控制协议(Transmission Control Protocol),简称TCP.安全

基本传输过程为:性能优化

  1. 上层将数据包交给传输层
  2. 传输层会在数据包前面附加上UDP 头,组成新的 UDP 数据包,再将新的 UDP 数据包交给网络层
  3. 网络层再将 IP 头附加到数据包上,组成新的 IP 数据包,并交给底层
  4. 数据包被传输到主机 B 的网络层,在这里主机 B 拆开 IP 头信息,并将拆开来的数据部分交给传输层
  5. 在传输层,数据包中的 UDP 头会被拆开,并根据 UDP 中所提供的端口号,把数据部分交给上层的应用程序
  6. 最终,数据包就发送到了主机 B 上层应用程序这里。

该题答案引用 《浏览器工做原理与实践》里的内容服务器

3. UDP和TCP有什么区别?

  • TCP协议在传送数据段的时候要给段标号;UDP协议不
  • TCP协议可靠;UDP协议不可靠
  • TCP协议是面向链接;UDP协议采用无链接
  • TCP协议负载较高,采用虚电路;UDP采用无链接
  • TCP协议的发送方要确认接收方是否收到数据段(3次握手协议)
  • TCP协议采用窗口技术和流控制
特性 TCP UDP
是否链接 面向链接 面向非链接
传输可靠性 可靠 不可靠
应用场合 传输大量数据 传输少许数据
速度

4. TCP传输的详细过程是怎样的?

进行三次握手,创建TCP链接。
  • 第一次握手:创建链接。客户端发送链接请求报文段,将SYN位置为1,Sequence Number为x;而后,客户端进入SYN_SEND状态,等待服务器的确认;
  • 第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,须要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,本身本身还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述全部信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
  • 第三次握手:客户端收到服务器的SYN+ACK报文段。而后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕之后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。 完成了三次握手,客户端和服务器端就能够开始传送数据。

ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0。 TCP协议规定,只有ACK=1时有效,也规定链接创建后全部发送的报文的ACK必须为1。 SYN(SYNchronization) : 在链接创建时用来同步序号。当SYN=1而ACK=0时,代表这是一个链接请求报文。对方若赞成创建链接,则应在响应报文中使SYN=1和ACK=1. 所以, SYN置1就表示这是一个链接请求或链接接受报文。 FIN (finis)即完,终结的意思, 用来释放一个链接。当 FIN = 1 时,代表此报文段的发送方的数据已经发送完毕,并要求释放链接。网络

发送HTTP请求,服务器处理请求,返回响应结果

TCP链接创建后,浏览器就能够利用HTTP/HTTPS协议向服务器发送请求了。服务器接受到请求,就解析请求头,若是头部有缓存相关信息如if-none-match与if-modified-since,则验证缓存是否有效,如有效则返回状态码为304,若无效则从新返回资源,状态码为200.session

关闭TCP链接
  • 第一次分手:主机1(可使客户端,也能够是服务器端),设置Sequence Number和Acknowledgment Number,向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了;
  • 第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,Acknowledgment Number为Sequence Number加1;主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“赞成”你的关闭请求;
  • 第三次分手:主机2向主机1发送FIN报文段,请求关闭链接,同时主机2进入LAST_ACK状态;
  • 第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,而后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段之后,就关闭链接;此时,主机1等待2MSL后依然没有收到回复,则证实Server端已正常关闭,那好,主机1也能够关闭链接了。

5. 为何不少站点第二次打开速度会很快?

主要缘由是第一次加载页面过程当中,缓存了一些耗时的数据。 那么,哪些数据会被缓存呢?

DNS缓存

主要就是在浏览器本地把对应的 IP 和域名关联起来,这样在进行DNS解析的时候就很快。

MemoryCache

是指存在内存中的缓存。从优先级上来讲,它是浏览器最早尝试去命中的一种缓存。从效率上来讲,它是响应速度最快的一种缓存。 内存缓存是快的,也是“短命”的。它和渲染进程“生死相依”,当进程结束后,也就是 tab 关闭之后,内存里的数据也将不复存在。

浏览器缓存

先看一张经典的流程图,结合理解

GitHub
浏览器缓存,也称Http缓存,分为强缓存和协商缓存。优先级较高的是强缓存,在命中强缓存失败的状况下,才会走协商缓存。

强缓存

强缓存是利用 http 头中的 ExpiresCache-Control 两个字段来控制的。强缓存中,当请求再次发出时,浏览器会根据其中的 expires 和 cache-control 判断目标资源是否“命中”强缓存,若命中则直接从缓存中获取资源,不会再与服务端发生通讯。

实现强缓存,过去咱们一直用expires。当服务器返回响应时,在 Response Headers 中将过时时间写入 expires 字段。像这样

expires: Wed, 12 Sep 2019 06:12:18 GMT
复制代码

能够看到,expires 是一个时间戳,接下来若是咱们试图再次向服务器请求资源,浏览器就会先对比本地时间和 expires 的时间戳,若是本地时间小于 expires 设定的过时时间,那么就直接去缓存中取这个资源。

从这样的描述中你们也不难猜想,expires 是有问题的,它最大的问题在于对“本地时间”的依赖。若是服务端和客户端的时间设置可能不一样,或者我直接手动去把客户端的时间改掉,那么 expires 将没法达到咱们的预期。

考虑到 expires 的局限性,HTTP1.1 新增了Cache-Control字段来完成 expires 的任务。expires 能作的事情,Cache-Control 都能作;expires 完成不了的事情,Cache-Control 也能作。所以,Cache-Control 能够视做是 expires 的彻底替代方案。在当下的前端实践里,咱们继续使用 expires 的惟一目的就是向下兼容。

cache-control: max-age=31536000
复制代码

在 Cache-Control 中,咱们经过max-age来控制资源的有效期。max-age 不是一个时间戳,而是一个时间长度。在本例中,max-age 是 31536000 秒,它意味着该资源在 31536000 秒之内都是有效的,完美地规避了时间戳带来的潜在问题。

Cache-Control 相对于 expires 更加准确,它的优先级也更高。当 Cache-Control 与 expires 同时出现时,咱们以 Cache-Control 为准。

协商缓存

协商缓存依赖于服务端与浏览器之间的通讯。协商缓存机制下,浏览器须要向服务器去询问缓存的相关信息,进而判断是从新发起请求、下载完整的响应,仍是从本地获取缓存的资源。若是服务端提示缓存资源未改动(Not Modified),资源会被重定向到浏览器缓存,这种状况下网络请求对应的状态码是 304。

协商缓存的实现,从 Last-ModifiedEtag,Last-Modified 是一个时间戳,若是咱们启用了协商缓存,它会在首次请求时随着 Response Headers 返回:

Last-Modified: Fri, 27 Oct 2017 06:35:57 GMT
复制代码

随后咱们每次请求时,会带上一个叫 If-Modified-Since 的时间戳字段,它的值正是上一次 response 返回给它的 last-modified 值:

If-Modified-Since: Fri, 27 Oct 2017 06:35:57 GMT
复制代码

服务器接收到这个时间戳后,会比对该时间戳和资源在服务器上的最后修改时间是否一致,从而判断资源是否发生了变化。若是发生了变化,就会返回一个完整的响应内容,并在 Response Headers 中添加新的 Last-Modified 值;不然,返回如上图的 304 响应,Response Headers 不会再添加 Last-Modified 字段。

使用 Last-Modified 存在一些弊端,这其中最多见的就是这样两个场景:

  • 咱们编辑了文件,但文件的内容没有改变。服务端并不清楚咱们是否真正改变了文件,它仍然经过最后编辑时间进行判断。所以这个资源在再次被请求时,会被当作新资源,进而引起一次完整的响应——不应从新请求的时候,也会从新请求。
  • 当咱们修改文件的速度过快时(好比花了 100ms 完成了改动),因为 If-Modified-Since 只能检查到以秒为最小计量单位的时间差,因此它是感知不到这个改动的——该从新请求的时候,反而没有从新请求了。

这两个场景其实指向了同一个 bug——服务器并无正确感知文件的变化。为了解决这样的问题,Etag 做为 Last-Modified 的补充出现了。

Etag 是由服务器为每一个资源生成的惟一的标识字符串,这个标识字符串能够是基于文件内容编码的,只要文件内容不一样,它们对应的 Etag 就是不一样的,反之亦然。所以 Etag 可以精准地感知文件的变化。

Etag 的生成过程须要服务器额外付出开销,会影响服务端的性能,这是它的弊端。所以启用 Etag 须要咱们审时度势。正如咱们刚刚所提到的——Etag 并不能替代 Last-Modified,它只能做为 Last-Modified 的补充和强化存在。

Etag 在感知文件变化上比 Last-Modified 更加准确,优先级也更高。当 Etag 和 Last-Modified 同时存在时,以 Etag 为准。

Service Worker Cache

Service Worker 是一种独立于主线程以外的 Javascript 线程。它脱离于浏览器窗体,所以没法直接访问 DOM。这样独立的个性使得 Service Worker 的“我的行为”没法干扰页面的性能,这个“幕后工做者”能够帮咱们实现离线缓存、消息推送和网络代理等功能。咱们借助 Service worker 实现的离线缓存就称为 Service Worker Cache。

Service Worker 的生命周期包括 install、active、working 三个阶段。一旦 Service Worker 被 install,它将始终存在,只会在 active 与 working 之间切换,除非咱们主动终止它。这是它能够用来实现离线存储的重要先决条件.

Push Cache

Push Cache 是指 HTTP2 在 server push 阶段存在的缓存。这块的知识比较新,应用也还处于萌芽阶段,应用范围有限不表明不重要——HTTP2 是趋势、是将来。在它还未被推而广之的此时此刻,我仍但愿你们能对 Push Cache 的关键特性有所了解:

  • Push Cache 是缓存的最后一道防线。浏览器只有在 Memory Cache、HTTP Cache 和 Service Worker Cache 均未命中的状况下才会去询问 Push Cache。
  • Push Cache 是一种存在于会话阶段的缓存,当 session 终止时,缓存也随之释放。
  • 不一样的页面只要共享了同一个 HTTP2 链接,那么它们就能够共享同一个 Push Cache。

参考资料

  • 极客时间《浏览器工做原理与实践》
  • 掘金小册子《前端性能优化原理与实践》

最后

  • 整理不易,麻烦各位给我点个赞~~
  • 了解更多内容,欢迎关注个人blog, 给我个star~~
  • 以为内容有帮助能够关注下个人公众号 「前端Q」,一块儿学习成长~~
    GitHub