从输入浏览器到页面展示涉及的缓存机制

从用户在浏览器地址栏输入 URL 到页面最终展示,整个过程中涉及多层缓存机制,这些缓存共同作用,提高网页加载速度和用户体验。以下是详细介绍:

1. DNS 缓存

当输入 URL 后,首先需要进行 DNS 解析,将域名转换为 IP 地址,这个过程涉及以下缓存:

  • 浏览器 DNS 缓存:浏览器会缓存之前查询过的域名解析结果

  • 操作系统 DNS 缓存:如果浏览器缓存中没有,会查询操作系统的 DNS 缓存

  • 路由器 DNS 缓存:家庭或公司网络的路由器也会缓存 DNS 记录

  • ISP 的 DNS 服务器缓存:互联网服务提供商的 DNS 服务器维护的缓存

// 查看Chrome浏览器的DNS缓存(在开发者工具中执行)
chrome.net.dns.getResolveInfo("example.com", (result) => {
  console.log(result);
});

2. TCP 连接缓存

建立 TCP 连接时也有缓存机制:

  • TCP 连接复用:HTTP/1.1 的 Keep-Alive 和 HTTP/2 的多路复用允许在同一 TCP 连接上发送多个请求

  • TCP Fast Open:允许在握手过程中发送数据,减少往返时间

3. 网络请求缓存

3.1 浏览器 HTTP 缓存

  • 强缓存:通过Cache-ControlExpires头控制

  • 协商缓存:通过ETagLast-Modified头实现

// 服务器返回的响应头示例
Cache-Control: max-age=3600
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 21 Oct 2020 07:28:00 GMT

3.2 Service Worker 缓存

Service Worker 作为 Web 应用程序与浏览器之间的代理服务器,可以拦截网络请求并缓存资源:

// Service Worker注册
navigator.serviceWorker.register("/sw.js");

// 在sw.js中缓存资源
self.addEventListener("install", (event) => {
  event.waitUntil(
    caches.open("v1").then((cache) => {
      return cache.addAll([
        "/",
        "/styles/main.css",
        "/scripts/main.js",
        "/images/logo.png",
      ]);
    })
  );
});

// 拦截请求并从缓存中响应
self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

3.3 CDN 缓存

内容分发网络在全球各地的节点上缓存静态资源,减少请求延迟:

  • 边缘节点缓存:离用户最近的 CDN 节点缓存内容

  • 区域节点缓存:CDN 的中间层缓存

  • 源站缓存:CDN 源站的缓存层

4. 浏览器渲染过程中的缓存

4.1 资源缓存

  • 内存缓存(Memory Cache):加载过的资源存储在内存中,页面关闭后失效

  • 硬盘缓存(Disk Cache):持久化存储的 HTTP 缓存,关闭浏览器后仍然有效

4.2 渲染缓存

  • 脚本编译缓存:V8 引擎会缓存编译后的 JavaScript 代码

  • 字体缓存:已下载的 Web 字体会被缓存

  • 图片缓存:解码后的图片数据会被缓存

// 检查资源是否来自缓存
performance.getEntriesByType("resource").forEach((resource) => {
  if (resource.transferSize === 0) {
    console.log(`${resource.name} 来自缓存`);
  }
});

4.3 DOM/CSSOM 缓存

  • DOM 缓存:浏览器会缓存构建好的 DOM 树

  • CSSOM 缓存:样式计算结果会被缓存

5. 应用层缓存

5.1 LocalStorage 和 SessionStorage

// 使用LocalStorage缓存数据
localStorage.setItem("user", JSON.stringify({ name: "张三", id: 123 }));

// 读取缓存数据
const user = JSON.parse(localStorage.getItem("user"));

5.2 IndexedDB

// 打开IndexedDB数据库
const request = indexedDB.open("myDatabase", 1);

// 创建对象存储
request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const store = db.createObjectStore("users", { keyPath: "id" });
};

// 存储数据
request.onsuccess = (event) => {
  const db = event.target.result;
  const transaction = db.transaction(["users"], "readwrite");
  const store = transaction.objectStore("users");
  store.put({ id: 1, name: "李四", age: 35 });
};

5.3 Web Storage API (Cache API)

// 打开缓存
caches.open("app-v1").then((cache) => {
  // 添加资源到缓存
  cache.add("/api/data.json");

  // 或者添加多个资源
  cache.addAll(["/styles/app.css", "/scripts/app.js"]);
});

// 从缓存获取资源
caches.match("/api/data.json").then((response) => {
  if (response) {
    return response.json();
  }
});

6. 预加载缓存

浏览器的预加载机制也会影响缓存:

  • DNS 预解析<link rel="dns-prefetch" href="//example.com">

  • 预连接<link rel="preconnect" href="//example.com">

  • 预获取<link rel="prefetch" href="/page-2.html">

  • 预渲染<link rel="prerender" href="/page-likely-to-be-visited-next.html">

总结

这些缓存机制在不同层面协同工作,共同提高网页加载性能。在实际开发中,合理利用这些缓存机制,可以显著提升用户体验,减少服务器负载和带宽消耗。

最后更新于

这有帮助吗?