彻底讲透浏览器缓存机制,吊打面试官

第一层:幼儿园阶段 ------ 为什么要有缓存?

首先要明白一个铁律:网络请求很慢,内存和硬盘很快

想象一下:你是一位厨师(浏览器),客人(用户)点了一份宫保鸡丁(网页)。

没有缓存

  • 每次客人来,你都要打电话去农场(服务器)问:"有鸡肉吗?有花生吗?"
  • 农场说"有",你再等快递送过来
  • 客人饿晕了,页面还在转圈

有缓存

  • 第一次做完宫保鸡丁,你把菜谱和食材存进冰箱(本地缓存)
  • 下次客人点同样的菜,直接从冰箱拿,5秒上桌
  • 农场偶尔打电话告诉你:"菜谱更新了",你再同步一下

缓存的本质:用空间(本地存储)换时间(网络延迟),同时保证数据新鲜度。


第二层:小学阶段 ------ 缓存的"三级冰箱"

浏览器有三层缓存,像俄罗斯套娃,层层查找:

复制代码
Service Worker(离线缓存)→ Memory Cache(内存缓存)→ Disk Cache(磁盘缓存)→ Push Cache(HTTP/2推送缓存)→ 网络请求

1. Service Worker Cache(私藏小金库)

  • 位置:浏览器主线程之外,独立运行
  • 特点:开发者完全控制,可以离线访问
  • 场景:PWA应用,飞机模式下也能刷知乎

2. Memory Cache(案板上的食材)

  • 位置:内存(RAM)
  • 特点:极快(纳秒级),但容量小,页面关闭就消失
  • 存储内容:Base64图片、小体积JS/CSS、当前页面的资源

3. Disk Cache(冰箱冷冻层)

  • 位置:硬盘(SSD/HDD)
  • 特点:较慢(毫秒级),容量大,持久保存
  • 存储内容:大文件、不常变的资源、跨会话共享

4. Push Cache(服务员提前备菜)

  • 位置:HTTP/2连接内
  • 特点:服务器主动推送,未被使用就丢弃(会话期内)
  • 场景:HTTP/2 Server Push,提前把可能需要的资源塞过来

查找顺序:Service Worker → Memory → Disk → Push → 网络

面试考点 :为什么同样的资源,刷新页面后from memory cache变成from disk cache

  • 首次加载:资源进Memory + Disk
  • 刷新页面:HTML重新解析,原Memory缓存被清,从Disk恢复
  • 新开标签:跨标签共享Disk缓存

第三层:中学阶段 ------ HTTP缓存协议(协商 vs 强缓存)

这是面试最高频的考点,两种缓存策略像两条不同的保鲜规则:

强缓存(Freshness Strategy)------ 看保质期

浏览器不问服务器,直接拿本地缓存。

判断依据ExpiresCache-Control

复制代码
┌─────────────────────────────────────────┐
│  浏览器:这包薯片保质期到明天,今天能吃吗?  │
│  自己看标签 → 能吃 → 直接吃(不发请求)      │
└─────────────────────────────────────────┘

HTTP头

yaml 复制代码
Expires: Wed, 21 Oct 2025 07:28:00 GMT  # 绝对时间(HTTP/1.0,已过时)

Cache-Control: max-age=31536000         # 相对时间,秒(HTTP/1.1,推荐)
Cache-Control: no-cache                 # 可以存,但每次要协商
Cache-Control: no-store                 # 完全不存,隐私数据
Cache-Control: private                  # 仅浏览器存,CDN不存
Cache-Control: public                   # 大家都能存

状态码200 (from disk cache)200 (from memory cache)

协商缓存(Validation Strategy)------ 问仓库还有没有

缓存过期了,但不确定服务器有没有新版本,带着"证据"去问

判断依据Last-Modified/If-Modified-SinceETag/If-None-Match

arduino 复制代码
┌─────────────────────────────────────────┐
│  浏览器:这包薯片过期了,但看起来没坏?      │
│  打电话给仓库:"批次号A123,还有货吗?"     │
│  仓库:"还是A123,没换" → 304 Not Modified  │
│  仓库:"现在批次B456了" → 200 + 新货       │
└─────────────────────────────────────────┘

HTTP头

yaml 复制代码
# 方案A:时间戳(秒级精度,可能不准)
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT  # 请求头

# 方案B:内容指纹(优先级更高,精确到字节)
ETag: "33a64df5"  # 服务器生成的唯一标识(文件内容哈希)
If-None-Match: "33a64df5"  # 请求头

状态码304 Not Modified(没改,用缓存)或 200(改了,重新下载)

完整决策流程(必背)

yaml 复制代码
┌─────────────┐
│  发起请求    │
└──────┬──────┘
       ▼
┌─────────────────┐
│ Service Worker? │──Yes──► 查SW缓存 ──► 有?返回 : 走网络
└────────┬────────┘ No
         ▼
┌─────────────────┐
│  有Cache-Control?│──No──► 查Expires ──► 过期?走协商 : 走强缓存
└────────┬────────┘ Yes
         ▼
┌─────────────────┐
│ max-age过期了? │──No──► 200 from cache(强缓存命中)
└────────┬────────┘ Yes
         ▼
┌─────────────────┐
│  有ETag?        │──Yes──► 发If-None-Match ──► 304? 用缓存 : 200更新
└────────┬────────┘ No
         ▼
┌─────────────────┐
│  有Last-Modified?│──Yes──► 发If-Modified-Since ──► 304? 用缓存 : 200更新
└────────┬────────┘ No
         ▼
    直接请求新资源

口诀:先强缓存(看时间),再协商(问指纹),最后才下载。


第四层:大学阶段 ------ 缓存的"暗坑"与黑魔法

坑点1:Cache-Control 的"障眼法"

yaml 复制代码
Cache-Control: no-cache

误区 :以为不能缓存?
真相 :可以缓存,但每次用之前必须协商(问服务器能不能用)。

yaml 复制代码
Cache-Control: no-store

真相 :这才是真正的禁止缓存,敏感数据用这个。

ini 复制代码
Cache-Control: max-age=0

效果 :等于 no-cache,立即过期,走协商。

坑点2:ETag 的"分布式灾难"

场景:负载均衡,3台服务器轮询

bash 复制代码
请求1 → 服务器A → ETag: "abc-123"
请求2 → 服务器B → ETag: "abc-456"  # 同样内容,不同ETag!
请求3 → 服务器C → ETag: "abc-789"

后果:明明内容没变,ETag不同导致缓存失效,反复下载。

解决

  • Last-Modified 替代(时间戳一致)
  • 或配置服务器用内容哈希生成ETag(MD5相同则ETag相同)
  • 或加 Cache-Control: public 让CDN统一处理

坑点3:304 的"性能陷阱"

误区 :304没下载内容,所以很快?
真相 :304仍然要建立TCP连接(HTTPS还要TLS握手),发送HTTP请求,等待服务器响应。

优化 :强缓存直接本地读取,零网络开销

数据对比

  • 强缓存:0ms,本地磁盘读取
  • 304协商:50-200ms,取决于RTT
  • 200重新下载:100ms-数秒,取决于资源大小

坑点4:Vary 头的"缓存分裂"

makefile 复制代码
Vary: Accept-Encoding, User-Agent

作用 :告诉缓存服务器,哪些请求头不同就要存不同版本

后果

  • Accept-Encoding: gzip → 存压缩版
  • Accept-Encoding: br → 存Brotli版
  • User-Agent: Mobile → 存移动端版

:Vary头太多 → 缓存爆炸,命中率暴跌。


第五层:博士阶段 ------ 缓存一致性模型(强一致性 vs 最终一致)

缓存失效的三种策略(计算机科学的终极难题)

策略 描述 适用场景
Cache-Aside(旁路缓存) 应用先查缓存,没命中查DB,再回填缓存 读多写少,最常用
Read-Through(直读) 缓存没命中自动查DB,对应用透明 需要缓存中间件(如Redis)
Write-Through(直写) 写缓存同时写DB,同步完成 强一致性要求
Write-Behind(异步写) 先写缓存,异步批量写DB 高性能,容忍短暂不一致
Refresh-Ahead(预刷新) 缓存即将过期时自动后台更新 热点数据,不允许击穿

浏览器特有的"新鲜度计算"(Heuristic Freshness)

场景 :服务器没给 Cache-Control 也没给 Expires,但给了 Last-Modified

浏览器黑魔法

scss 复制代码
新鲜期 = (当前时间 - Last-Modified时间) × 10%

比如文件一年前修改,浏览器认为能缓存 365天 × 10% = 36.5天

面试杀招 :解释为什么"啥也没配"的资源也会被缓存,以及为什么这是不可靠的(各浏览器算法不同)。

缓存污染与中毒(安全视角)

攻击场景

  1. 攻击者请求 script.js?callback=alert(1)
  2. CDN/浏览器缓存了这个带恶意回调的版本
  3. 正常用户请求 script.js(不带参数),但缓存命中了带毒版本

防御

yaml 复制代码
Cache-Control: no-cache  # 有查询字符串就不缓存
# 或
Vary: Query-String        # 不同参数不同缓存

第六层:上帝视角 ------ 现代浏览器的缓存架构演进

从单进程到多进程:缓存的"线程安全"

上古时代

  • 所有标签页共享一个缓存目录
  • 标签A缓存的JS,标签B直接读取
  • 问题:崩溃一个标签,全浏览器缓存损坏

现代架构(Chrome Site Isolation)

css 复制代码
浏览器进程(Browser Process)
    ↓
网络服务进程(Network Service)← 统一处理HTTP缓存
    ↓
渲染进程A(Renderer)──┐
渲染进程B(Renderer)──┼── 通过Mojo IPC访问缓存,相互隔离
渲染进程C(Renderer)──┘

关键改进:HTTP缓存由独立进程管理,Renderer崩溃不影响缓存完整性。

磁盘缓存的"物理结构"(Chrome的SimpleCache)

perl 复制代码
磁盘缓存目录
├── index          # 索引文件(快速查找)
├── data_0         # 数据块文件(小块资源)
├── data_1
├── data_2
├── data_3
├── f_000001       # 大文件(独立存储)
├── f_000002
└── ...

存储策略

  • 小文件(<16KB):存 data_* 块文件,减少碎片
  • 大文件:独立 f_xxxxxx 文件,避免阻塞小文件读取
  • 内存映射:热点索引常驻内存,磁盘IO异步化

缓存淘汰算法(LRU+优先级混合)

Chrome使用改进的LRU

css 复制代码
优先级 = 访问频率 × 时间衰减 + 资源类型权重

HTML/JS/CSS:高权重(页面核心)
图片:中权重
视频:低权重(体积大,但可能不再看)

淘汰顺序

  1. 先删低优先级 + 最久未访问
  2. 磁盘空间不足时,触发后台清理
  3. 用户可手动"清除浏览数据"

第七层:Service Worker ------ 缓存的"终极形态"

从"浏览器控制"到"开发者控制"

ini 复制代码
// sw.js - 拦截所有请求,完全自定义缓存策略
self.addEventListener('fetch', event => {
    event.respondWith(
        caches.match(event.request).then(response => {
            // 1. 缓存命中?直接返回
            if (response) return response;
            
            // 2. 否则走网络
            return fetch(event.request).then(networkResponse => {
                // 3. 动态更新缓存
                caches.open('v1').then(cache => {
                    cache.put(event.request, networkResponse.clone());
                });
                return networkResponse;
            });
        })
    );
});

缓存策略矩阵(Google推荐)

策略 代码模式 适用场景
Cache First 先查缓存,没命中再网络 静态资源,离线优先
Network First 先网络,失败再缓存 API数据,实时性优先
Stale-While-Revalidate 立即返回缓存,后台更新 新闻列表,快速+新鲜兼顾
Cache Only 只用缓存 纯离线应用
Network Only 只用网络 实时性极强(股票行情)

背景同步(Background Sync)------ 离线提交的救赎

ini 复制代码
// 用户离线时提交表单
navigator.serviceWorker.ready.then(registration => {
    registration.sync.register('submit-form');
});

// SW中处理
self.addEventListener('sync', event => {
    if (event.tag === 'submit-form') {
        event.waitUntil(
            // 网络恢复后自动重试
            sendFormDataFromIndexedDB()
        );
    }
});

第八层:CDN 与边缘缓存 ------ 缓存的"全球化"

多层缓存架构

markdown 复制代码
用户浏览器 ──► CDN边缘节点 ──► 源站服务器
     │              │              │
  Memory/      Memory/Disk/      Disk/DB
  Disk Cache   全局分布式缓存     原始数据

CDN缓存的"回源策略"

指令 含义
Cache-Control: s-maxage=3600 CDN共享缓存1小时(覆盖max-age)
CDN-Cache-Control: max-age=3600 专用CDN头(Cloudflare等支持)
Surrogate-Control: max-age=3600 另一种CDN专用头

缓存穿透、击穿、雪崩(经典面试三连)

问题 现象 解决
穿透 查询不存在的数据,每次都打到DB 布隆过滤器,或缓存空值
击穿 热点key过期,瞬间大量请求打DB 互斥锁,或逻辑过期(永不过期,异步刷新)
雪崩 大量key同时过期,DB崩溃 随机过期时间,多级缓存,熔断降级

浏览器层面的防御

ini 复制代码
// Stale-While-Revalidate 模式防止击穿
const cache = await caches.open('api-cache');
const cached = await cache.match(request);

// 立即返回缓存(即使过期)
if (cached) {
    // 后台异步更新
    fetch(request).then(response => cache.put(request, response.clone()));
    return cached;
}

第九层:实战优化 ------ 从"能用"到"极速"

项目场景 1:高频迭代的 B 端管理系统(如:飞书、钉钉网页版)

  • 业务特点

    1. 代码量巨大(JS 动辄 5MB 以上)。
    2. 版本更新极快(可能每天都要修复 Bug 发版)。
    3. 痛点:发版后,由于浏览器缓存了旧的 JS,用户报错(缓存不一致),或者发版后用户加载太慢。
  • 极致优化方案(Webpack + Nginx)

    • 第一步(基础) :Webpack 配置 contenthash。如果只改了"客户模块"的代码,打包出来的 customer.a1b2.js 名字变了,但"合同模块" contract.c3d4.js 名字不变。
    • 第二步(Nginx 调优)
      • index.html 设置 no-cache:每次打开页面,浏览器都得问服务器"菜单换了吗?"。
      • 对 JS/CSS 设置 public, max-age=31536000, immutable
    • 解决的实际问题
      1. 秒开 :用户第二次打开飞书,除了 HTML 那个几十字节的请求,所有几 MB 的 JS 全部从本地磁盘 0ms 读取,完全不走网络
      2. 更新不报错 :发版后,HTML 里的 JS 路径变成了新哈希,浏览器发现名字变了,自动下载新代码。旧代码在缓存里互不干扰,彻底解决"发版后要清缓存"的低级 Bug

项目场景 2:内容型 App 或 社交平台(如:小红书、今日头条)

  • 业务特点

    1. 首页是长列表(Feed 流)。
    2. 用户对"白屏"极度敏感,多转一秒圈圈就要关掉 App。
    3. 痛点:每次点开 Feed 流,都要等接口返回(数据协商),用户会看到 1-2 秒的 Loading 动画。
  • 极致优化方案(SWR / staleTime 模式)

    • 项目实践 :使用 React QuerySWR 库请求首页列表接口。
    • 配置 :设置 staleTime: 5分钟
    • 解决的实际问题
      1. 消灭 Loading 圈圈 :用户在 5 分钟内反复切换页面,数据直接从内存缓存 拿,瞬间呈现,完全没有加载状态
      2. "先看后换" :如果超过 5 分钟,用户点开时,页面先展示上次留下的旧数据 (不白屏),同时后台静默发请求,等新笔记刷出来了,再无感替换。这就是用户感觉这些 App 运行飞快的核心秘密。

项目场景 3:在线教育或视频平台(如:B站、慕课网)

  • 业务特点

    1. 视频分片文件(.ts 文件)非常多且大。
    2. 用户喜欢反复看同一个知识点(反复拖动进度条)。
    3. 痛点 :浏览器默认的 Disk Cache(磁盘缓存)像个"黑盒",空间满了会随机删文件。用户回头看一段视频时,发现刚才看过的片段被浏览器偷偷删了,又得重新缓冲,浪费流量且卡顿。
  • 极致优化方案(IndexedDB 手动存储)

    • 项目实践 :在网页端写一个 VideoCache 类,利用 Service Worker 拦截视频请求。
    • 逻辑
      1. 视频下载后,不交给浏览器自动管,而是由代码强行存入 IndexedDB(这是浏览器里一个几百 MB 到几 GB 的永久数据库)。
      2. 下次进度条拖回来,代码先去 IndexedDB 查:"这个片段我有吗?"如果有,直接转成 Blob 给播放器。
    • 解决的实际问题
      1. 省钱:公司带宽费大幅下降,因为用户反复看同一个视频,流量消耗为 0。
      2. 极致丝滑 :即便用户断网了,只要之前看过的部分,进度条随便拖,完全不缓冲

总结:我该怎么选?

你的项目类型 核心要用的缓存技术 一句话理由
普通的网站 / B端后台 Webpack 哈希 + Nginx Immutable 保证发版不报错,重复访问 0 耗时。
手机端 Feed 流 / 实时看板 SWR (stale-while-revalidate) 消灭 Loading 转圈,让用户感觉"数据瞬间就在那"。
大文件 / 离线优先 / 播放器 Service Worker + IndexedDB 绕过浏览器不可控的清理机制,实现持久化的二进制存储。

面试对话示范:

面试官 :你在项目中怎么做缓存优化的? :我会分场景。比如在我们那个 [XX 管理系统] 里,我利用 Webpack 的 contenthash 配合 Nginx 的 immutable 头部,把静态资源加载耗时降到了 0ms;而在 [XX 首页 Feed 流] 中,我为了解决接口返回慢导致的白屏,引入了 SWR 机制,先用旧缓存渲染 UI 提升首屏速度,再后台静默更新。


第十层:未来趋势 ------ 缓存的" Web 3.0 时代"

1. 从"存响应"到"存数据":结构化缓存

  • 现在的痛点(为什么虚) : 现在的 Cache API 就像一个死板的仓库 。你存了一个 5MB 的 JSON 接口响应,如果你只想查"价格 > 100"的商品,你必须先把整个 JSON 读进内存,用 JS 去遍历。这太费内存和 CPU 了
  • 落地的业务场景大型离线应用(如:Figma、在线文档、移动端商城)
    • 未来进化 :浏览器尝试将 IndexedDB(数据库)和 Cache API(网络缓存)融合。
    • 面试谈资 :你可以说:"现在的缓存是 URL 维度的 ,未来的缓存应该是 数据维度的。像 Google 正在推进的存储标准,就是希望让 Service Worker 能直接对缓存的二进制数据流进行搜索和过滤,而不是全量解析,这对低端机极其友好。"

2. 从"手动预取"到"AI 智能猜": Speculation Rules API

  • 现在的痛点(为什么虚) : 现在的 Preload(预加载)是程序员硬编码的。代码写死:用户点"详情页"时加载"评论插件"。 问题是:有的用户根本不看评论,你白白浪费了用户的流量。
  • 落地的业务场景新闻资讯流(如:今日头条、知乎)
    • 现在的技术动作 :Google 已经推出了 Speculation Rules API。它不再是简单的标签,而是一套动态规则。
    • AI 的介入 :浏览器观察用户的路径。如果 90% 的人在看完文章后会点开"相关推荐",浏览器会在后台自动、低优先级地缓存下个页面的内容。
    • 面试谈资 :你可以聊 "预测性性能优化"。这比单纯的缓存更超前,它是在用户还没动作时,通过浏览器的学习模型实现"零时延切换"。

3. 从"中心化"到"邻居互传":去中心化缓存(P2P)

  • 现在的痛点(为什么虚) : 现在的缓存路径是:你 → CDN → 源站。 问题是:双 11 时,CDN 也会崩;而且公司要付给 CDN 供应商巨额的流量费。
  • 落地的业务场景大型游戏资源下载(如:米哈游网页端、在线高清视频)
    • 核心逻辑:如果我邻居刚才看过了《流浪地球2》,我再看的时候,浏览器能不能直接从邻居的电脑(或路由器)里通过局域网把缓存切片传给我?而不必再去几千公里外的服务器拿?
    • 面试谈资 :你可以提到 "内容寻址缓存"。现在的缓存是按"链接"找,未来是按"内容指纹(Hash)"找。即便链接变了,只要文件内容一样,就能从全球网络任何一个节点获取,这能帮公司省下 70% 的 CDN 费用。

终极回答策略:从协议深度到架构广度的四维阐述

1. 核心定性(展现系统思维)

"我认为浏览器缓存不是孤立的几个 HTTP 头,而是一套由多方协同的复杂调度系统 。它向下对接底层的浏览器内核存储(Memory/Disk),向上承接前端工程化的构建产物(Webpack/Vite),向外延伸至全球分布的 CDN 节点。它的本质是在数据新鲜度(Freshness) 、**加载延迟(Latency)网络成本(Cost)**之间寻找业务最优解。"

2. 决策链路(展现协议精度)

"在实际执行中,我将其总结为**'两级验证、零 RTT 追求'**。

  • 第一级是本地自校验 :优先匹配 Cache-Control。我的准则是'静态资源全量 immutable,入口文件严格 no-cache',以此追求绝对的 0 RTT
  • 第二级是云端再确认 :当强缓存失效,通过 ETag 进行字节级比对。我会特别关注分布式环境下的 ETag 漂移问题,确保 304 命中率不因多台服务器生成的指纹不一致而崩盘。"

3. 工程落地(展现全栈理解)

"缓存策略必须与 CI/CD 流程深度绑定。

  • 构建层 ,通过 contenthash 实现'文件内容即标识',让长效强缓存成为可能。
  • 应用层 ,通过 Stale-While-Revalidate(SWR)模式,将网络请求异步化。即'先用旧数据渲染 UI,后台静默更新缓存',彻底消除用户感知的 Loading 状态,实现**'瞬时响应'**的极致 UX。"

4. 架构设计(展现大厂视野)

"针对大型复杂应用,我会设计**'三层递进式存储架构'**:

  • L1(动态拦截层) :利用 Service Worker 自定义缓存策略,处理离线可用和高频接口拦截。
  • L2(标准协议层):严格遵循 HTTP 语义,利用磁盘缓存存储海量静态资源。
  • L3(边缘算力层) :在 CDN 边缘节点完成 Vary 头的逻辑判断或 A/B 测试注入,减少回源压力。 这种设计能让首屏时间(FCP)在各种网络环境下保持在 300ms 级别。"

避坑指南:面试中的 3 个"反直觉"细节(必考点)

细节点 你的深度回答(加分项)
no-cache 的字面陷阱 "不要被名字误导,no-cache 并不禁用缓存,它只是强制每次使用前必须通过协商确认。真正禁写磁盘的是 no-store。"
304 的隐藏成本 "304 虽省流量但不省时间。在高延迟环境下(RTT > 100ms),一次 304 协商可能比下载一个 10KB 的文件更慢,所以强缓存才是性能的终点。"
Vary 头的副作用 "慎用 Vary: User-Agent。它会让 CDN 为成千上万个浏览器版本各存一份缓存,导致命中率雪崩,甚至拖垮源站。"

终极速记卡片(临考前 30 秒看这个)

  • 一个中心:以消除 RTT(往返时延)为中心。
  • 两个基本点:强缓存看保质期(过期前不问),协商缓存看指纹(过期了再问)。
  • 三项黑科技immutable(刷新不重验)、SWR(先吃陈粮再换新米)、Service Worker(离线救星)。
  • 四对头Expires/Cache-Control vs Last-Modified/ETag

速记核心关键词

面试前记住这 5 个关键词,串联整个知识网:

关键词 含义
两级验证 强缓存(时间)+ 协商缓存(指纹)
三级存储 Memory → Disk → Service Worker
四对头 Cache-Control/Expires + ETag/Last-Modified
304陷阱 协商仍有开销,强缓存才是极致性能
SW革命 开发者接管缓存,离线优先成为可能

最后一句面试杀招

"优秀的缓存策略不是配置几个HTTP头,而是深入理解浏览器从内存到磁盘、从本地到CDN的完整缓存链路,让数据在最合适的位置以最合适的形态存在,在性能、新鲜度和一致性之间找到业务最优解。"

相关推荐
米丘1 小时前
了解 window.history 和 window.location, 更好地掌握 vue-router、react-router单页面路由
前端
zone77391 小时前
006:RAG 入门-面试官问你,RAG 为什么要切块?
后端·算法·面试
swipe1 小时前
箭头函数与 this 面试题深度解析:从原理到实战
前端·javascript·面试
星_离2 小时前
《Vue 自定义指令注册技巧:从手动到自动,效率翻倍》
前端·vue.js
狗头大军之江苏分军2 小时前
消耗 760万 Token 后,一文看懂了“小龙虾” OpenClaw 和 OpenCode 的区别
前端·后端
毛骗导演2 小时前
万字解析 OpenClaw 源码架构-安全与权限
前端·架构
哇哇哇哇2 小时前
vue3 ref解析
前端
哇哇哇哇2 小时前
vue3 reactive解析
前端
光影少年2 小时前
Vue的响应式原理?Vue2和Vue3有什么区别?
前端·vue.js·掘金·金石计划