大文件Markdown渲染逻辑

大文件Markdown渲染逻辑

下面我给你把10 万行 Markdown(每行是一张图片 URL)在网页中展示时,浏览器与服务器之间的真实图片请求逻辑讲得非常清楚,分 有预览 / 无预览 两种情况,并解释虚拟列表、懒加载、浏览器缓存、滚动触发机制等实际工作流。

✅ 一、核心原则:浏览器只会对进入视口或即将进入视口的资源发起请求

浏览器不会因为你加载了整个 MD 文本,就把里面所有图片一口气全部请求。

真正控制图片请求的是:

•	是否渲染了 <img>
•	是否使用 loading="lazy"
•	是否用了虚拟列表(Virtual Scroll)
•	缓存策略 (HTTP Cache)
•	是否有预览模式(例如缩略图 vs 原图)

🧨 二、无预览——直接显示图片(最常见)

🧯场景:10 万行 Markdown,每行 <img src="xxx">

浏览器不会一次性请求这 10 万张图

流程如下:

✔ 1. 首屏:进入视口的 <img> 才会发起请求

一般视口同时能显示几十张图片(取决于图片高度)。

👉 只有这几十张图片的网络请求会真正发出。

✔ 2. 有 loading="lazy" 的懒加载

默认现代浏览器给 Markdown 渲染出的 <img> 会自动懒加载:

<img src="xxx.jpg" loading="lazy">

懒加载逻辑是:

状态 是否请求图片?

图片进入视口 请求

图片接近视口(约 300~800px) 预请求

图片离视口很远 不会请求

✔ 3. 下翻滚动时产生新请求

你往下翻时,浏览器会:

•	销毁或移除上方已经滚出视口的 DOM(如果用了虚拟列表)
•	渲染新进入视口的 <img>
•	对这些 <img> 触发请求

❗不会重复请求(命中缓存)

如果图片 URL 不变:

•	memory cache(页面存在)立即加载,不走网络
•	disk cache(刷新后)走 disk,不走远程服务器
•	只有第一次加载才访问服务器

✔ 4. 即使 10 万行,浏览器最多请求几十张

总结一句话:

图片会随着你的滚动逐步请求,不会一次性下载全部。

🖼 三、有预览(缩略图)模式

如果你页面的逻辑是:

列表 预览图(小图)

点击后 加载大图(原图)

则请求逻辑变成两级:

✔ 1. 列表滚动时:只加载小图(thumbnail)

例如:

小图

滚动时只会加载缩略图——通常几十 KB。

✔ 2. 用户点开预览:再请求原图

例如:

https://img.example.com/full/123.jpg

只有在用户点击预览时才发起大图请求。

效果:极大减少流量 & 加载压力

🧱 四、虚拟列表(Virtual Scroll)的情况

如果你使用:

•	React Window
•	Vue Virtual List
•	React Virtualized
•	或自写虚拟滚动组件

那逻辑会更极端:

✔ 只渲染屏幕中 + 上下 buffer 区的几十行

真正的 DOM 中大概只有:

50~200 行图片节点

其余 99,800 行根本不渲染,也不会发出任何请求。

这让 10 万行页面毫无压力。

🔍 五、总结表:有预览 / 无预览 的请求行为

情况 滚动时是否请求图片? 最大请求数量 是否重复请求?

无预览、直接 <img> ✔ 是 屏幕能容纳的图数量(几十个) ❌ (缓存)

有预览小图 ✔ 是,但只请求缩略图 几十个 ❌

点击预览原图 ✔ 请求大图 1 ❌

使用虚拟列表 ✔ ~50–200 ❌

不使用懒加载 ❗可能加载更多(视图开始渲染时) 可能上千 一样缓存

🧠 六、你滚到 10 万行最底部,总共请求了多少?

✔ 理论上:

~(视口可见数量 + buffer)× 2 遍(上下滚)

比如:

•	可见 30 行
•	buffer 100 行

你完整滚一遍,只会加载:

约 200 × 2 = 400 张图片左右

而不是 100,000 张。