wuyanqian0503 / blogs

1 stars 0 forks source link

浏览器工作原理与实践 以及 浏览器访问一个url的过程 #25

Open wuyanqian0503 opened 3 years ago

wuyanqian0503 commented 3 years ago

目录

浏览器的架构

TCP协议:如何保证页面文件能被完整送达浏览器?

TCP协议Q&A

TCP/IP协议簇与OSI模型

HTTP请求流程

浏览器访问一个url的过程

渲染进程是如何渲染页面的

关于合成线程对事件的处理,进一步了解passive的作用,以及如查找到目标元素

wuyanqian0503 commented 3 years ago

01|浏览器架构

早期浏览器单进程: 不稳定 不流畅 不安全

现代多进程架构: 主进程、渲染进程、插件进程、GPU进程、网络进程

主进程(Browser进程)

主要负责界面显示、用户交互、子进程管理,同时提供存储等功能

渲染进程

核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页。 排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中。 默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。

渲染进程中存在以下线程:

1、GUI渲染线程

负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。 当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。

2、JS引擎线程

也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)

JS引擎线程负责解析Javascript脚本,运行代码。

JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序,JS是单线程的。

3、事件触发线程

接受浏览器里面的操作事件响应。 如在监听到鼠标、键盘等事件的时候, 如果有事件处理函数,就将对应的任务压入任务队列(添加到待处理队列的队尾),等待JS引擎的处理。 事件触发线程管理着一个任务队列。

PS:GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行; 如果JS执行的时间过长,会导致页面渲染被阻塞。

4、定时触发器线程

setInternal与setTimeout所在的线程。

浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)

因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)

GPU进程

最多一个,负责3D绘制,只有当该页面使用了硬件加速才会使用它,来渲染页面。否则的话,不使用这个进程,而是用Browser进程来渲染页面。

网络进程

主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。

第三方插件进程

主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。

Service worker

Service worker 是一种可以 web 开发者控制缓存的技术。如果 Service worker 被实现成从本地存储获取数据时,那么原本的请求就不会被浏览器发送给服务器了。 并且,Service worker的代码是在渲染进程中运行的。

打开一个页面至少需要四个进程

通常情况下,打开 1 个页面至少需要 1 个网络进程、1 个浏览器进程、1 个 GPU 进程以及 1 个渲染进程,共 4 个;如果打开的页面有运行插件的话,还需要再加上 1 个插件进程。

wuyanqian0503 commented 3 years ago

02|TCP协议:如何保证页面文件能被完整送达浏览器?

提前总结

在数据传输的过程中,IP协议通过IP地址将数据送到指定的主机,而UDP协议通过端口号来将数据分发给正确的应用程序,在此之前,TCP协议负责三次握手和数据包校验来保证数据传输的完整和可靠,不过也因此牺牲了数据包的传输速度

完整的TCP的连接可分为三个阶段,建立连接、传输数据和断开连接

为什么需要各种协议

从浏览器的角度来看,页面文件从服务器传送到浏览器的过程其实就是数据传输的过程,互联网中的数据是通过数据包来传输的,而数据包在传输过程中容易丢失或出错。那么在网络发展的过程中,为了使互联网中的各方都能正确接受到数据,渐渐发展出了一套各方都遵守的传输协议,这一整套协议被统称为TCP/IP协议簇,在实际的应用场景中,数据包传输的过程被划分为应用层、传输层、网络层、数据链路层以及物理层,所以,数据在经过每一层的传输时都需要遵循一定的协议,而UDP协议和TCP协议就是属于传输层的协议,而IP协议则是属于网络层的。

名词

FP:First Paint 页面加载到首次开始绘制的时长,网络加载速度是其重要的影响因素 IP:Internet Protocol 网际协议 IP地址:计算机地址 UDP:用户数据包协议(User Datagram Protocol) TCP:传输控制协议(Transmission Control Protocol),是一种面向连接的、可靠的、基于字节流的传输层通信协议。

IP:把数据包送达目的主机

image

UDP:把数据包送达应用程序

“用户数据包协议(User Datagram Protocol)”,简称 UDP,UDP协议规定了和应用程序交互的规范。

UDP 中一个最重要的信息是端口号,每个想访问网络的程序都需要绑定一个端口号。 通过端口号 UDP 就能把指定的数据包发送给指定的程序了,所以 IP 通过 IP 地址信息把数据包发送给指定的电脑,而 UDP 通过端口号把数据包分发给正确的程序。

和 IP 头一样,端口号会被装进 UDP 头里面,UDP 头再和原始数据包合并组成新的 UDP 数据包。UDP 头中除了目的端口,还有源端口号等信息。

UDP协议传输存在两个问题:

TCP:把数据完整地送达应用程序

基于UDP传输存在的两个缺陷,我们提出了TCP协议, TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。相对于 UDP,TCP 有下面两个特点:

image

TCP连接的生命周期

一个完整的 TCP 连接的生命周期包括了“建立连接”“传输数据”和“断开连接”三个阶段。 image

首先,建立连接阶段。这个阶段是通过“三次握手”来建立客户端和服务器之间的连接。我们说,TCP 提供面向连接的通信传输。这里面向连接是指在数据通信开始之前先做好两端之间的准备工作。所谓三次握手,是指在建立一个 TCP 连接时,客户端和服务器总共要发送三个数据包以确认连接的建立。

其次,传输数据阶段。在该阶段,接收端需要对每个数据包进行确认操作,也就是接收端在接收到数据包之后,需要发送确认数据包给发送端。所以当发送端发送了一个数据包之后,在规定时间内没有接收到接收端反馈的确认消息,则判断为数据包丢失,并触发发送端的重发机制。同样,一个大的文件在传输过程中会被拆分成很多小的数据包,这些数据包到达接收端后,接收端会按照 TCP 头中的序号为其排序,从而保证组成完整的数据。

最后,断开连接阶段。数据传输完毕之后,就要终止连接了,涉及到最后一个阶段“四次挥手”来保证双方都能断开连接。

由这个过程可以看出,TCP 为了保证数据传输的可靠性,牺牲了数据包的传输速度,因为“三次握手”和“数据包校验机制”等把传输过程中的数据包的数量提高了一倍。

TCP协议的一些补充

1. HTTP协议和TCP协议的关系

都是TCP/IP协议簇的子集。

HTTP协议属于应用层,TCP协议属于传输层,HTTP协议位于TCP协议的上层。

请求方要发送的数据包,在应用层加上HTTP头以后会交给传输层的TCP协议处理,应答方接收到的数据包,在传输层拆掉TCP头以后交给应用层的HTTP协议处理。建立 TCP 连接后会顺序收发数据,请求方和应答方都必须依据 HTTP 规范构建和解析HTTP报文。

2. 浏览器的不同标签是否是同一端口,接收数据后如何确认是哪一个标签

端口一样的,浏览器的网络进程知道每个tcp链接所对应的标签是那个,所以接收到数据后,会把数据分发给对应的渲染进程

3. http 和 websocket都是属于应用层的协议吗?

是的,他们都是应用层协议,而且websocket名字取的比较有迷惑性,其实和socket完全不一样,你可以把websocket看出是http的改造版本,增加了服务器向客户端主动发送消息的能力。

4. TCP传送数据时 浏览器端就做渲染处理了么?如果前面数据包丢了 后面数据包先来是要等么?类似的那种实时渲染怎么处理?针对数据包的顺序性?

接收到http响应头中的content-type类型时就开始准备渲染进程了,响应体数据一旦接受到便开始做DOM解析了!基于http不用担心数据包丢失的问题,因为丢包和重传都是在tcp层解决的。http能保证数据按照顺序接收的。(也就是说,从tcp到http的数据就已经是完整的了,即便是实时渲染,如果发生丢包也得在重传后才能开始渲染)

下层为上层提供服务 image

wuyanqian0503 commented 3 years ago

03 | HTTP请求流程

HTTP 是一种允许浏览器向服务器获取资源的协议,是 Web 的基础

浏览器端发起 HTTP 请求流程

  1. 构建请求 首先,浏览器构建请求行信息(如下所示),构建好后,浏览器准备发起网络请求。
GET /index.html HTTP1.1
  1. 查找缓存 在真正发起网络请求之前,浏览器会先在浏览器缓存中查询是否有要请求的文件。其中,浏览器缓存是一种在本地保存资源副本,以供下次请求时直接使用的技术。
wuyanqian0503 commented 3 years ago

TCP/IP协议簇

TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。

TCP/IP参考模型是事实上的国际标准,即现实生活中被广泛使用的网络参考模型。

TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。

TCP/IP协议共有5层,各层实现的协议也有所不同,各层的主要协议如下: image

每一层也都工作着不同的设备:

image

OSI模型

一个试图使各种计算机在世界范围内互连为网络的标准框架, 学术上和法律上的国际标准,是完整的权威的网络参考模型。 image

关于OSI与TCP/IP的关系

简单地说: OSI参考模型是学术上和法律上的国际标准,是完整的权威的网络参考模型。 而TCP/IP参考模型是事实上的国际标准,即现实生活中被广泛使用的网络参考模型。

具体的区别:

  1. 首先TCP/IP他是一个协议簇;而OSI(开放系统互联)则是一个模型,且TCP/IP的开发时间在OSI之前。
  2. TCP/IP是由一些交互性的模块做成的分层次的协议,其中每个模块提供特定的功能;OSi则指定了哪个功能是属于哪一层的。
  3. TCP/IP是五层结构,而OSI是七层结构。OSI的最高三层在TCP中用应用层表示。
wuyanqian0503 commented 3 years ago

浏览器访问一个url的过程

Step 1: 输入处理

浏览器主进程会判断输入的url是不是一个有效的地址,如果是的话,

Step 2: 访问开始

浏览器借助网络进程发起一个请求,这里会先进行DNS查找域名,然后网络进程会通过适当的网络协议如TCP、http等协议发起请求。 当服务器返回给浏览器重定向请求时,网络线程会通知 UI 线程需要重定向,然后会以新的地址做开始请求资源。

Step 3: 处理响应数据

当网络进程收到来自服务器的响应后,会试图根据响应头中的Content-Type字段来判断返回的数据的格式。 当返回的格式是HTML时,则会通知渲染进程准备渲染工作,如果是zip等类型的格式,则会利用下载管理器做进一步的文件预览或者下载的工作。

在开始渲染之前,网络线程要先检查数据的安全性,这里也是浏览器保证安全的地方。如果返回的数据来自一些恶意的站点,网络线程会显示警告的页面。同时,Cross Origin Read Blocking(CORB)策略也会确保跨域的敏感数据不会被传递给渲染进程。

Step 3:准备渲染进程

当所有的检查结束后,网络线程确信浏览器可以访问站点时,网络进程通知主进程数据已经准备好了。主进程会根据当前的站点找到一个渲染进程完成接下来的渲染工作。

这个渲染进程其实在第二个步骤中就已经开始准备了。

Step 4:提交访问

在所有的数据和渲染进程都准备完毕后,浏览器主进程会通过IPC向渲染进程提交这次访问。同时也会保证渲染进程在渲染的同时依然可以请求数据。 一旦浏览器进程收到来自渲染进程的确认完毕的消息,就意味着访问的过程结束了,文档渲染的过程就开始了。

这时,地址栏显示出表明安全的图标,同时显示出站点的信息。访问历史中也会加入当前的站点信息。为了能恢复访问历史信息,当页签或窗口被关闭时,访问历史的信息会被存储在硬盘中。

Extra Step:加载完毕

当访问被提交给渲染进程,渲染进程会继续加载页面资源并且渲染页面。当渲染进程"结束"渲染工作,会给浏览器进程发送消息,这个消息会在页面中所有子页面(frame)结束加载后发出,也就是 onLoad 事件触发后发送。当收到"结束"消息后,UI 线程会隐藏页签标题上的加载状态图标,表明页面加载完毕。

但这里"结束"并不意味着所有的加载工作都结束了,因为可能还有 JavaScript 在加载额外的资源或者渲染新的视图。

访问不同的站点

一次普通的访问到此就结束了。当我们输入另外一个地址时,浏览器进程会重复上面的过程。但是在开始新的访问前,会确认当前的站点是否关心beforeunload事件。

beforeunload事件可以提醒用户是否要访问新的站点或者关闭页签,如果用户拒绝则新的访问或关闭会被阻止。

由于所有的包括渲染、运行 Javascript 的工作都发生在渲染进程中,浏览器进程需要在新的访问开始前与渲染进程确认当前的站点是否关心unload。

wuyanqian0503 commented 3 years ago

渲染进程是如何渲染页面的

大致的过程如下:

  1. 解析html构建DOM
  2. 加载额外资源如img、link、script,当遇到script时会停止解析html等待资源加载并执行完毕后再继续解析,可以利用defer或者async属性来延迟或者异步加载和执行
  3. 计算样式:通过CSS和浏览器内置样式来计算
  4. 布局:遍历DOM树得到和DOM树相似的具有元素坐标和尺寸信息的布局树
  5. 绘制:得到绘制顺序
  6. 合成:合成线程将层分块并借助光栅线程光栅化来得到合成帧,交给GPU渲染

解析HTML文档来创建DOM

当渲染进程接收到来自浏览器进程提交访问的消息后就开始接受 HTML 数据,主线程开始解析 HTML 文本字符串,并且将其转化成 Document Object Model(DOM)。

额外资源的加载

在解析HTML的同时,还进行着预加载扫描(Preload Scanner),当预加载扫描在分析器分析 HTML 过程中发现了类似 img 或 link 这样的标签时,就会发送请求给网络进程,而渲染进程会根据这些额外资源是否会阻塞转化过程而决定是否等待资源加载完毕。

JavaScript 会阻塞转化过程

当 HTML 分析器发现 Githubissues.

  • Githubissues is a development platform for aggregating issues.