• 浏览器输入url到页面展示过程


           这个问题在面试中属于一个高频问题,80%以上会被问到,而且大家也能说出一二,其实这个问题是可以深挖的,如果你回答的有深度,在很大程度上影响面试官对你的印象。

    一、URL输入

    首先我们是在浏览器中输入URL,URL中文名叫做统一资源定位符 (俗称网址),统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

    主要组成部分:protocol (协议): // hostname(主机名)[:port] (端口) / path(路径) / [;parameters] (参数)

    协议默认端口号传输协议
    http80超文本传输协议
    https443在http的基础上进行了安全设置(SSL/TSL)证书认证
    ftp21主要用于客户端电脑和服务器端的文件传输

    这里我们要注意浏览器遵循的同源策略,我们前端访问接口的时候通常会遇到跨域的问题,这里所有的域是协议、域名和端口号的合集,同域就是协议、域名和端口号均相同,否则会发生跨域,如何解决跨域可参考我之前的文章  什么是跨域,怎么解决跨域?

    二、DNS域名解析 

    在网络进程接收到 URL 后,并不是马上对指定 URL 进行请求。首先,我们需要进行 DNS 解析域名得到对应的 IP,然后通过 ARP 解析 IP 得到对应的 MAC(Media Access Control Address)地址。

    域名是我们取代 IP 记忆复杂 的一种解决方案,IP 地址才是目标在网络中所被分配的节点。MAC 地址是对应目标网卡所在的固定地址。

    DNS 解析域名主要分为以下几步
    ①.询问浏览器 DNS 缓存
    ②.询问本地操作系统 DNS 缓存(即查找本地 host 文件)
    ③.询问 ISP(Internet Service Provider)互联网服务提供商(例如电信、移动)的 DNS 服务器
    ④.询问根服务器,这个过程可以进行递归和迭代两种查找的方式,两者都是先询问顶级域名服务器查找

    三、建立通讯 

    DNS解析获取到服务器的IP+端口后,接下来就是要建立TCP链接,这里就涉及到我们常说的“三次握手”。

    首先,判断是不是https,如果是,则HTTPS其实是HTTP + SSL/TLS 两部分组成,也就是在HTTP基础上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。 可参考之前文章 https建立连接过程

    三次握手,建立TCP连接

    ①.第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
    ②.第二次握手:服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为 x+1;同时,自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
    ③.第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTAB_LISHED状态,完成TCP三次握手。

    seq序号:用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记
    ack确认序号:只有ACK标志位为1,确认序号字段才有效,ack=seq+1

    标识位:
    ACK:确认标识,用于表示对数据包的成功接收
    SYN:同步标识,表示TCP连接已初始化,发起一个新连接
    FIN:完成标识,释放一个连接,用于拆除上一个SYN标识。一个完整的TCP连接过程一定有SYN和FIN包。

    四次挥手,关闭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等待主机2 MSL后依然没有收到回复,则证明主机2已正常关闭,那好,主机1也可以关闭连接了。

    四、浏览器渲染

    浏览器会根据资源类型进行处理,比如 gzip 压缩后的文件则进行解压缩,如果响应头 Content-type 是 text/html,则开始解析HTML。

    按照渲染的时间顺序,流水线可以分为下面几个子阶段:构建DOM树、样式计算、布局阶段、分层、栅格化和显示。

    ①.渲染进程将HTML内容转换为浏览器能够读懂的DOM树结构。

    ②.渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets,计算出DOM节点的样式。

    ③.创建布局树,并计算元素的布局信息。

    ④.对布局树进行分层,并生成分层树。

    ⑤.为每个图层生成绘制列表,并将其提交到合成线程。

    ⑥.合成线程将图层分图块,并栅格化将图块转换成位图。

    ⑦.合成线程发送绘制图块命令给浏览器进程。浏览器进程根据指令生成页面,并显示到显示器上。

    五、构建DOM树

    浏览器从网络或硬盘中获得HTML字节数据后,会先将HTML的原始字节数据转换为文件指定编码的字符,然后浏览器会根据HTML规范来将字符串转换为各种令牌标签,如html、body等,最终解析成一个树状的对象模型,就是DOM树。

    具体步骤如下所示:

    ①.转码:读取接收到的HTML二进制数据,按指定编码格式将字节转换为HTML字符串

    ②.Tokens化:解析HTML,将HTML字符串转换为结构清晰的Tokens,每个Token都有特殊的含义,同时又自己的一套规则

    ③.构建Nodes:每一个Node都添加特定的属性或属性访问器,通过指针能够确定Node的父、子、兄弟关系和所属treeScope

    ④.构建DOM树:最重要的工作就是建立起每个节点的父子兄弟关系。


    解析过程中遇到图片、link、script会启动下载。

    script标签会阻塞 DOM 树的构建,所以一般将 script 放在底部,或者添加 async 、defer 标识。

    css 下载时异步,不会阻塞浏览器构建 DOM 树,但是会阻塞渲染,布局阶段会等待 css 下载解析完毕后才进行。

    样式计算
    渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets,计算出DOM节点的样式。

    样式计算过程主要有两步:
    ①.属性值标准化:先将所有值转换为渲染引擎容易理解的、标准化的计算值。在CSS文本中有很多属性值,如em、blue、bold等等,这些类型值不容易被渲染引擎理解,所以需要进行转换。
    ②.处理样式的继承和层叠,计算出DOM树中每个节点的具体样式。

    CSS样式来源主要有3种:
    ①.通过link引用的外部css文件
    ②.style标签内的css
    ③.元素的style属性内嵌的css


    布局阶段
    布局过程,即排除script、meta等功能化、非视觉节点,排除 display:none 的节点,计算元素的位置信息,确定元素的位置,构建一棵只包含可见元素布局树。

    分层
    页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-index 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。

    并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。

    图层绘制
    渲染引擎实现图层的绘制:把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表。

    绘制列表中的指令非常简单,就是让其执行一个简单的绘制操作,比如绘制粉色矩形或者黑色的线等。

    栅格化
    合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。

    通常一个页面可能很大,但是用户只能看到其中的一部分,我们把用户可以看到的这个部分叫做视口(viewport)。在有些情况下,有的图层可以很大,比如有的页面你使用滚动条要滚动好久才能滚动到底部,但是通过视口,用户只能看到页面的很小一部分,所以在这种情况下,要绘制出所有图层内容的话,就会产生太大的开销,而且也没有必要。

    显示
    最后,合成线程发送绘制图块命令给浏览器进程。浏览器进程根据指令生成页面,并显示到显示器上,渲染过程完成。

    页面渲染优化方案有哪些?

    ①.HTML文档结构层次尽量少,最好不深于六层;

    ②.脚本尽量后放,放在前即可;

    ③.少量首屏样式内联放在标签内

    ④.样式结构层次尽量简单

    ⑤.在脚本中尽量减少DOM操作,尽量缓存访问DOM的样式信息,避免过度触发回流;

    ⑥.减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;

    ⑦.动画尽量使用在绝对定位或固定定位的元素上;

    ⑧.隐藏在屏幕外,或在页面滚动时,尽量停止动画;

    ⑨.尽量缓存DOM查找,查找器尽量简洁;

    ⑩.涉及多域名的网站,可以开启域名预解析。

  • 相关阅读:
    【Android安全】Android中的Intent
    ESP32 Arduino实战基础篇-使用中断和定时器
    【面试题】java后端开发实习(含答案)
    c++头文件模板
    2023烟台大学计算机考研信息汇总
    关于蓝绿发布(Blue-Green Deployment)
    ES6相关语法规范
    goland 远程调试 remote debug
    CancerLLM: 癌症领域的大型语言模型
    [Ubuntu, Ajax Nx]C++调用python报from import错误
  • 原文地址:https://blog.csdn.net/qq_34402069/article/details/127686353