浏览器相关原理(面试题)详细总结一
1. chrome 打开一个页面需要启动多少进程?分别有哪些进程?
浏览器从关闭状态进行启动,然后新开 1 个页面至少需要 1 个网络进程、1 个浏览器进程、1 个 gpu 进程以及 1 个渲染进程,共 4 个进程;后续再新开标签页,浏览器、网络进程、gpu进程是共享的,不会重新启动,如果2个页面属于同一站点的话,并且从a页面中打开的b页面,那么他们也会共用一个渲染进程,否则新开一个渲染进程。
最新的 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 进程。 -
网络进程
:主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。 -
插件进程
:主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
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
.
基本传输过程为:
- 上层将数据包交给传输层
- 传输层会在数据包前面附加上
udp 头
,组成新的 udp 数据包,再将新的 udp 数据包交给网络层 - 网络层再将 ip 头附加到数据包上,组成新的 ip 数据包,并交给底层
- 数据包被传输到主机 b 的网络层,在这里主机 b 拆开 ip 头信息,并将拆开来的数据部分交给传输层
- 在传输层,数据包中的 udp 头会被拆开,并根据 udp 中所提供的端口号,把数据部分交给上层的应用程序
- 最终,数据包就发送到了主机 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.
关闭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 关闭以后,内存里的数据也将不复存在。
浏览器缓存
先看一张经典的流程图,结合理解
浏览器缓存,也称http缓存,分为强缓存和协商缓存。优先级较高的是强缓存,在命中强缓存失败的情况下,才会走协商缓存。
强缓存
强缓存
是利用 http 头中的 expires
和 cache-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-modified
到 etag
,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。
参考资料
- 极客时间《浏览器工作原理与实践》
- 掘金小册子《前端性能优化原理与实践》
最后
- 欢迎加我微信(winty230),拉你进技术群,长期交流学习...
-
欢迎关注「前端q」,认真学前端,做个有态度的技术人...
最后
- 欢迎加我微信(winty230),拉你进技术群,长期交流学习...
欢迎关注「前端q」,认真学前端,做个有态度的技术人...
![https://raw.githubusercontent.com/luckywinty/blog/master/images/qrcode_for_gh_f9d37093c0ed_1280.jpg)
下一篇: 这一家做家务搞笑经典