浏览器渲染过程与懒加载

125 阅读7分钟

从浏览器输入网址到网页被渲染出来的过程: 当你在浏览器地址栏输入一个网址并按下回车键后,整个网页从请求到渲染的过程可以分为以下几个步骤:


1. DNS 解析

  • 目的:将你输入的域名(如 www.example.com)解析成一个具体的 IP 地址(如 192.0.2.1),因为网络通信依赖 IP 地址。
  • 过程
    1. 浏览器会首先检查缓存(浏览器缓存、本地缓存、系统缓存)中是否有该域名的解析记录。
    2. 如果缓存没有找到,则会向 DNS 服务器发送查询请求,逐级解析直到获得对应的 IP 地址。
    3. 最终,DNS 解析返回一个目标服务器的 IP 地址。

2. 建立 TCP 连接

  • 目的:通过网络与目标服务器建立通信通道。
  • 过程:使用 TCP/IP 协议,浏览器与目标服务器之间通过三次握手建立连接:
    1. 客户端发送 SYN:浏览器向服务器发送请求建立连接的信号(SYN)。
    2. 服务器响应 SYN-ACK:服务器接收到 SYN 后,确认可以建立连接,并返回 SYN-ACK。
    3. 客户端发送 ACK:客户端确认连接,发送 ACK,连接建立完成。

如果是 HTTPS 请求,还会在此基础上进行 TLS/SSL 握手,用于建立加密通信。


3. 浏览器发送 HTTP 请求

  • 目的:向目标服务器请求网页资源。
  • 过程
    1. 浏览器根据用户输入的网址构造一个 HTTP 请求报文,内容包括:
      • 请求方法(GET、POST 等)。
      • URL 路径(如 /index.html)。
      • 请求头(包含浏览器类型、支持的格式等信息)。
    2. 报文通过已建立的 TCP 通道发送到目标服务器。

4. 服务器处理请求并返回响应

  • 目的:服务器接收并处理请求,返回网页内容。
  • 过程
    1. 服务器接收浏览器的请求,根据 URL 路径定位到对应的资源(如 HTML 文件)。
    2. 如果资源是动态内容(如使用 PHP、Node.js 等生成的页面),服务器会运行后端代码生成 HTML 内容。
    3. 服务器构造 HTTP 响应报文,包括:
      • 响应状态码(如 200、404)。
      • 响应头(如内容类型、缓存指令)。
      • 响应体(如 HTML 文件)。
    4. 服务器将响应报文通过 TCP 通道发回给浏览器。

5. 浏览器解析和渲染网页

  • 目的:将服务器返回的 HTML 文件和相关资源(CSS、JS、图片等)加载并渲染成可视化的网页。
  • 过程
    1. HTML 解析

      • 浏览器从响应体中读取 HTML 内容,开始构建 DOM 树
      • 如果遇到外部资源(如 CSS、JavaScript、图片等),会发送新的请求获取这些资源。
    2. CSS 解析

      • 下载并解析 CSS 文件,构建 CSSOM 树
      • 与 DOM 树结合形成 渲染树
    3. JavaScript 执行

      • 下载并执行 JavaScript 文件。
      • 可能会修改 DOM 或 CSSOM,触发重新渲染。
    4. 渲染树布局和绘制

      • 布局(Layout):根据渲染树计算每个元素的位置和大小。
      • 绘制(Painting):将布局结果绘制到屏幕上。

6. 用户与网页交互

  • 网页完全渲染后,用户可以与页面内容交互(如点击按钮、填写表单等)。
  • 用户的操作可能触发 JavaScript 事件,从而引起 DOM 的变化或向服务器发送新的请求。

整体流程图

1. 输入网址
   ↓
2. DNS 解析
   ↓
3. 建立 TCP 连接(三次握手)
   ↓
4. 发送 HTTP/HTTPS 请求
   ↓
5. 服务器返回响应
   ↓
6. 浏览器解析和渲染(HTML、CSS、JS)
   ↓
7. 网页展示并交互

涉及的核心技术

  1. DNS(域名解析系统):负责将域名翻译为 IP 地址。
  2. HTTP/HTTPS:负责客户端与服务器之间的数据通信。
  3. TCP/IP:传输层和网络层协议,确保数据可靠传输。
  4. 浏览器渲染引擎:负责将 HTML、CSS、JS 转换为页面。

常见的优化点

  1. DNS 缓存:减少域名解析的时间。
  2. CDN 加速:通过内容分发网络提供就近的资源加载。
  3. 压缩资源文件:通过 Gzip 或 Brotli 减小文件大小。
  4. 懒加载:延迟加载图片或其他资源,提高页面加载速度。
  5. HTTP/2:支持多路复用,减少请求阻塞。

懒加载(Lazy Loading)是一种优化资源加载和使用的技术,指的是当页面或应用加载时,只加载当前需要的资源,将其他资源的加载延迟到真正需要的时候(如用户滚动到某个位置时)。它的主要目的是提升首屏加载速度减少不必要的资源消耗


懒加载的核心概念

  • 普通加载:页面加载时会一次性加载所有资源(图片、脚本、数据等),即使某些资源并不立即需要。
  • 懒加载:页面加载时只加载必要的资源,其他资源延后加载,比如等到用户实际需要时(如滚动到可见区域)。

懒加载的应用场景

  1. 图片懒加载

    • 网页中大量图片时,只加载用户当前视口中可见的图片,其余图片在用户滚动到它们的可见范围时再加载。
    • 示例:电商网站的产品列表、博客中的文章图片。
  2. 视频懒加载

    • 视频文件体积较大,懒加载可以只在用户点击播放或滚动到视频可见区域时才开始加载。
    • 示例:新闻网站的视频内容。
  3. 数据懒加载(分页加载)

    • 页面只加载当前的分页数据,当用户滚动到页面底部时再加载下一页的数据。
    • 示例:社交媒体的无限滚动、商品列表的分页加载。
  4. 组件懒加载(前端框架)

    • 在单页应用(SPA)中,某些页面或功能模块用到的代码并不需要在初次加载时全部加载,可以将它们延迟到用户访问对应页面时才加载。
    • 示例:React 的动态 import、Vue 的异步组件。

图片懒加载的实现方法

1. 使用 HTML 原生属性

现代浏览器支持 <img>loading="lazy" 属性,简单方便:

<img src="example.jpg" alt="Example" loading="lazy">
  • loading="lazy" 会让图片仅在用户滚动到图片的可见区域时加载。

2. 使用 JavaScript 实现懒加载

通过监听页面的滚动事件,判断图片是否进入视口,进入视口后再加载。

传统实现(Intersection Observer API)

document.addEventListener("DOMContentLoaded", function () {
  const lazyImages = document.querySelectorAll('img[data-src]');

  const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src; // 将真实图片地址赋值给 src
        img.removeAttribute('data-src');
        observer.unobserve(img);
      }
    });
  });

  lazyImages.forEach(img => observer.observe(img));
});
  • 解释
    • 给图片设置一个 data-src 属性来存放真实的图片地址,而 src 设置为占位图片或空。
    • 使用 Intersection Observer 检测图片是否进入视口(即是否可见)。
    • 当图片进入视口时,将 data-src 的值赋值给图片的 src,从而加载真实图片。

3. 使用第三方库

有许多现成的懒加载库,封装好了各种功能,可以快速实现懒加载:

  • LazyLoad.js
  • Lazysizes
  • Lozad.js

使用示例(以 Lazysizes 为例):

<img class="lazyload" data-src="example.jpg" alt="Example">
<script src="lazysizes.min.js"></script>
  • Lazysizes 会自动处理 data-src 并进行懒加载。

懒加载的优势

  1. 提升首屏加载速度
    • 页面初始加载时只获取必要资源,减少页面加载时间。
  2. 减少带宽消耗
    • 用户未滚动到的内容不会加载,可以节省带宽,特别是对图片和视频等大资源。
  3. 提升用户体验
    • 用户可以更快看到关键内容,避免因为加载大量无关资源而卡顿。

懒加载的潜在问题

  1. SEO 问题

    • 如果搜索引擎的爬虫不支持懒加载实现方式,可能会导致某些内容无法被索引(尤其是图片和异步加载的数据)。
    • 解决办法:对重要内容使用服务端渲染(SSR)或预渲染工具(如 React 的 Next.js)。
  2. 不支持 JavaScript 的用户

    • 如果用户的浏览器禁用了 JavaScript,依赖 JS 实现的懒加载将失效。
    • 解决办法:使用 HTML 原生的 loading="lazy" 或设置合理的回退机制。
  3. 闪烁问题

    • 如果图片延迟加载,可能会导致页面在加载时内容发生跳动。
    • 解决办法:设置图片的占位符或固定宽高避免布局抖动。