网页渲染过程

1、URL

  • scheme://host.domain.port/path/filename
    • scheme :传输协议,http/https/file/ftp
    • host :定义域主机,http 默认的主机是www
    • domain :域名,如:baidu/google/taobao
    • path:定于服务器上的路径
    • filename :文档/资源名称,如:.html/.css/.js

2、DNS解析

DNS协议通过域名解析查找IP地址,或逆向从IP地址反查域名。DNS就是一个网络服务商,我们的域名解析就是在DNS上的一条记录

1、DNS缓存

  • 浏览器缓存:浏览器会按照一定频率记录DNS
  • 操作系统缓存:如果浏览器话黁中找不到需要的DNS,就去操作系统中查找
  • 路由器缓存:路由器也有DNS缓存
  • ISP的DNS服务器:互联网服务提供商有专门的DNS服务器查询对应的域名
  • 根服务器:.com

2、DNS优化

  • DNS缓存:
    • 浏览器缓存、操作系统缓存、路由器缓存、ISP缓存、根服务器缓存
    • 系统缓存(mac: /etc/hosts)
  • DNS负载均衡
    • 根据每台机器的负载量,返回 合适的机器IP给用户

3、发起TCP请求

1、TCP传输服务

  • 提供一种可靠的传输,这个过程面向连接的字节流服务。

2、三次握手

  • 第一次:客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND的状态,等待服务器确认
  • 第二次:服务器收到syn包,必须确认客户端的 syn(ack= x+!),同时自己也发送一个syn包 (Seq=y),syn+ack 包,此时服务器进入 SYN_RECV状态
  • 第三次:客户端收到服务器的syn+ack包,向服务器发送确认包 (ack=y+1),这个包发送完毕,客户端和服务器进入 ESTABLISHED状态,此时完成三次握手

3、四次挥手

  • 客户端发送一个FIN,用来关闭客户端到服务器的数据传送 FIN=1,序列号 seq=u(+!),进入FIN-WAIT-1的状态(终止等待-1)
  • 服务器收到FIN包后,发送一个ACK给对方并且带上自己的序列号sq,确认序列号为手打序号+1,服务器进入CLOSE-WAIT(关闭等待)状态。这个时候客户端已经没有数据要发送了,但是服务如果发送数据客户端依然要接受,这个状态要持续一段时间,即COLSE-WAIT状态的持续时间。
  • 服务器发送一个FIN,用来关闭服务器到客户端的数据传送,也就是告诉客户端,数据发送完了。假定此时的序列号是seq=为,服务器进入LAST-ACK(最后确认)状态,等待客户端的确认。
  • 主动关闭方(客户端)收到FIN后,发送一个ACK给服务端,确认序号是收到的序号+1,此时,客户端进入TIME-WAIT(时间等待)状态。服务器只要收到客户端发送的确认,立即进入CLOSE状态。客户端还需要等待2*MSL(最长报文寿命)后,才进入CLOSE状态。

4、发送HTTP

1、请求行

  • method Request-URL HTTP-version: GET index.html HTTP/1.1

2、GET和POST

  • GET比POST更不完全,因为参数直接暴露在URL上
  • GET通过URL传递参数,POST可以放在Rquest body
  • GET会产生一个TCP数据包,而POST会产生康哥TCP数据包(标准)

3、请求头

4、请求正文

5、HTTP缓存

1、强制缓存
  • 当缓存服务器中有客户端需要的数据,直接拿来用(数据没有实效)
  • Expires 和 Cache-Control
    • 现在大部分都用Cache-Control
      • private:客户端可以缓存
      • public:客户端和代理服务器都可以
      • max-age=t:缓存内容将在t秒后失效
      • no-catche:使用协商缓存
2、协商缓存
  • 也叫对比缓存,客户端会先从缓存数据库中拿到一个缓存的标识,然后向服务器端验证标识是否失效,如果没有实效,会返回304,这样客户端就可以之际去缓存数据库中拿出数据,如果失效,服务器端会返回新的数据。
    • Last-Modified:服务器咋相应请求时,告诉浏览器资源的最后修改时间。如果资源被修改,那么直接返回200,否则只需要传输respone header,返回304
    • Etag:相应服务器请求时候,通过此子端告诉浏览器当前资源在服务器生成的唯一标识(规则由服务器定)
3、通过缓存加快网页端的加载速度

5、服务器处理请求并返回HTTP报文

1、HTTP状态码

  • 1xx:请求已收到
  • 2xx:成功
  • 3xx :发生了重定向
    • 301:永久重定向
    • 302:临时重定向
  • 4xx :客户端错误-路径不正确/语法错误
    • 401:鉴权错误
    • 403:禁止
    • 404:没有找到网页
  • 5xx :服务器错误
    • 500:服务器内部错误
    • 502:服务器部署问题

2、响应报头

  • Server,Connection

3、响应报文

  • 请求的HTML、CSS等等

6、浏览器解析渲染页面

1、解析HTML形成DOM树

  • 根据当前HTML内容,将标签按照结构解析成DOM树,DOM树的解析过程是一个深度优先遍历的方式。即现构建当前节点的所有子节点,再构建下一个兄弟节点
  • 如果遇到script标签,则DOM树的构建会暂停,知道脚本下载并执行完成后继续构建

2、解析CSS形成CSSOM树

  • 解析CSS形成CSS规则树,解析CSS规则树时JS执行将会暂停,直到CSS规则树就绪
  • 浏览器在CSS规则树生成之前不会进行渲染

3、合并DOM树和CSSOM树形成渲染树

  • DOM树和CSSOM树都准备好了后,浏览器会开始构建渲染树。

4、根据渲染树计算每一个节点信息(布局Layout)

  • 布局:通过渲染树中渲染对象的信息,计算出每一个渲染对象的位置和尺寸
  • 回流:在布局完成后,发现某个部分发生了变化影响了布局,就需要倒回去重新渲染

5、根据计算好的信息绘制页面

  • 绘制阶段系统会遍历呈现树,并调用呈现器的"paint"方法,将呈现器的内容显示在屏幕上
  • 重绘:某个元素的背景颜色、文字颜色等。不影响元素周围或内部布局的属性,将只会引起浏览器的重绘
  • 回流:某个元素的尺寸发生变化,则需要重新计算渲染树
    • 触发回流的时机:
      • 首次渲染
      • 浏览器窗口大小发生变化
      • 元素尺寸或位置发生改变
      • 内容变化(文字内容)
      • 天假或删除DOM元素
      • 激活css伪类:hover
      • 查询某些属性或者调用某些方法
        • clientWidth
        • offsetWidth
        • getComputedStyle()
        • scrollTo()
  • 回流和重绘
    • 比如color、background-color、vsilillity等等,浏览器会将新样式赋予给元素并重新绘制它

7、JS解析

浏览器开始加载HTML页面,遇到<script>标签,会根据标签的属性(defer/async)来决定如何处理脚本

1、预解析

  • 同步脚本
  • async 异步脚本:会解析HTML,同时异步下载脚本。脚本下载完后,会暂停解析立即执行脚本,脚本执行完成后,继续解析HTML
  • defer 延迟脚本:会解析HTML。同时异步下载脚本。脚本会在HTML解析完成后,DOMContentLoaded触发前,按照脚本书写顺序依次执行。

2、浏览器引擎去执行JS:

  • V8(chorme)、JSCORE(safira)
  • 编译
    • 词法分析
    • 语法分析
    • 代码生成
    • 通过字节码去执行
  • 执行
    • 执行上下文和作用域
      • JS引擎会创建执行上下文(context),包含变量对象、作用域链和this
      • JS事件循环

8、页面渲染

当所有资源都加载和执行后,页面会显示给用户,这个过程会触发一些事件,如:DOMContentLoaded、load

1、定义:

  • 触发时机:当初始的HTML文档被完全加载和解析之后触发
  • 不等待资源:它不需要等待样式表(CSS)、图片(Images)、子框架(iframes)、异步脚本(带有async属性的script)加载完成
  • 目标对象:事件目标是 document,但会冒泡到 window。

2、DOMContentLoaded VS window.onload

|----------|-------------------------|-------------------------------------------------|
| 特性 | DOMContentLoaded | window.onload(load 事件) |
| 触发条件 | DOM树构建完成 | 页面所有资源(DOM + CSS + Images + iframes等)全部加载完成 |
| 触发速度 | (一般远早于onload) | (取决于图片、视频等资源大小) |
| 适用场景 | 操作DOM元素、绑定事件监听器、初始化UI逻辑 | 获取图片尺寸、操作Canvas、依赖外部资源完全加载的场景 |
| 多次绑定 | 支持多次添加监听器 | 通常只支持一个处理函数(若直接赋值 window.onload = ... 会覆盖之前的) |

3、执行事例

javascript 复制代码
// 1. HTML 解析开始
document.addEventListener('DOMContentLoaded', () => {
    console.log('1. DOM 解析完毕,可以操作 DOM 节点了');
    // 此时图片可能还没加载完
});

window.addEventListener('load', () => {
    console.log('2. 所有资源(包括图片)加载完毕');
});
// 3. HTML 解析结束,触发 DOMContentLoaded
// 4. 图片等资源加载结束,触发 load

9、常见问题及解决方案

1、<script>标签中的 async 和 defer。

1、用途:为什么需要 async 和 defer

没有属性的普通 <script>标签,遇到就会阻塞DOM解析,等它下载并执行完才会继续解析。如果脚本很大,页面就是白屏。async 和 defer 都能让脚本不阻塞DOM解析,DOM解析与脚本的下载过程是并行的,页面该解析解析。

2、区别:执行实际 + 顺序 + 与 DOMContentLoaded的关系

  • 执行顺序:
    • 普通script:遇到->下载->执行->继续解析
    • defer:遇到->异步下载(不阻塞)->DOM解析完成后->按书写顺序执行->触发DOMContebtLoaded。
    • async:遇到->异步下载->下载完成后立即执行(可能会阻塞解析)->执行完成后继续解析。(执行顺序不保证,谁先下载完谁先执行)
  • 关键区别:
    • 顺序:defer 保证顺序,async不保证顺序
    • 执行时机:defer在DOM解析完成后、DOMContentLoaded前执行。async脚本文件下载完成后会立即执行,可能会在解析过程中执行,从而影响DOM解析。
    • DOMContentLoaded触发:defer 会等待对应脚本执行完成后触发;async 不确定,如对应的脚本文件在DOM解析完成前下载并完成执行,不影响触发时机。

3、实际应用场景:选型

  • defer :多个脚本有依赖关系 (如jq在前,插件在后),或脚本需要操作完整的DOM
  • async独立脚本,不依赖其他脚本和DOM状态,比如埋点统计、广告脚本、第三方小程序。
  • 普通:远古方案,现在基本上被defer替代
  • 陷阱
    • 如果页面里有async的脚本在操作DOM,而DOM还没有解析完成,就可能报错,所以操作DOM的脚本不用async

2、点击切换样式,页面依旧卡顿掉帧?

1、业务分级,区分动态渲染和静态渲染。

动态频繁变更元素,直接脱离标准文档流,使用绝对定位布局,修改样式仅触发重绘,避免回流。静态固定展示元素,统一编写CSS类名,页面初始化一次性渲染完成,杜绝反复修改。

2、样式合并与兜底优化。

统一操作样式,摒弃逐行修改行内样式,通过切换class类名批量更改样式属性。DOM批量处理,新增页面元素使用文档碎片统一插入,减少页面渲染次数。硬件加速加持,动画家伙优先使用 transform 和 opacity,从根源避开回流触发条件。

3、架构层优化,降低渲染消耗。

长列表场景介入虚拟列表,只渲染可视区域DOM节点,从源头减少渲染压力。高频交互添加截流限制,滚动切换、点击联动操作限制执行频次,减少无效渲染。紧急场景降级开关,流量高峰关闭页面非必要动画特效,牺牲视觉效果有限保障页面流畅运行。

3、页面加载慢怎么优化?

1、优化方向:从"请求-渲染'全链路分层

  • 网络层:
    • DNS预解析(<link rel="dns-prefetch">);
    • 减少HTTP请求(合并、雪碧图、iconfont);
    • 开启HTTP/2(多路复用,减少队头阻塞);
    • CDN(不仅加速,还降低带宽压力;CDN能减少RTT、提升并发能力)
  • 资源层:
    • 压缩:Gzip/Brotli、图片WebP/AVIF;
    • 缓存:强缓存(Cache-Control) + 协商缓存(ETag);
    • 按需加载:路由懒加载、图片懒加载
  • 渲染层:
    • 关键渲染路径优化:内联关键CSS,异步加载非关键JS(defer/async);
    • 减少重排重绘:用transform 代替 left/top,读写DOM批量操作;
    • 骨架屏 + 预加载(<link rel="preload">)

2、定位问题:使用工具反向推理

  • 使用 Chrome DevTools 工具分析:
    • Network:看资源耗时;
    • Performance面板:看火焰图,分析是js执行时间长?解析HTML时间长?重排重绘频繁?
    • Lighthouse:给出具体的评分和优化建议
  • 从用户感知反推:
    • 首屏加载:用SSR或预渲染解决白屏问题
    • 交互可用:用代码分割,让首屏JS体积减小;
    • 慢网络:用Service Worker做离线缓存
  • 降级方案:兼容低端机,慢网络
    • 低质量图片,禁用非必要动画,减少长任务。

3、避坑:

  • CDN不是越多越好:多域名会增加DNS查询和连接开销,一般2~3个域名为宜
  • 合并请求不一定更快:在HTTP/2下,小请求可以并行执行,合并反而会造成"一个资源阻塞全部"。
  • 缓存不是越多越好:HTML不能强缓存太长,否则更新不生效。JS/CSS用内容哈希实现长效缓存。
相关推荐
问心无愧05135 分钟前
ctf show web入门110
前端·笔记
拉拉肥_King10 分钟前
Vue 3 主题切换深度解析:从炫酷动画到零闪烁方案
前端·vue.js
excel12 分钟前
为什么 Pinia + localForage 持久化后,页面初始化拿不到数据?
前端
雨雨雨雨雨别下啦15 分钟前
vant介绍
前端
小小小小宇15 分钟前
大模型失忆问题探讨
前端
wordbaby18 分钟前
rn-cross-calendar:一个兼容 React 18/19、RN/RNOH 的跨平台日历组件
前端·react native·harmonyos
weixin_5231853220 分钟前
Collections.unmodifiableMap详解:真的不可修改吗?
java·linux·前端
江米小枣tonylua21 分钟前
关掉 VSCode:在 NeoVim12 上配置 Claude Code
前端·程序员
2301_7736436231 分钟前
ceph镜像
前端·javascript·ceph
程序员黑豆1 小时前
AI全栈开发之Java:什么是JDK
前端·后端·ai编程