为何fetch获取资源生成Object URL再设iframe src,比直接设src更快?
问题
最近在为报表创建打印按钮,为保证跨浏览器一致性采用PDF版本。最初通过fetch()获取PDF,转为Blob后创建Object URL并设置为iframe的src。后来尝试直接将iframe的src设为PDF URL,却发现该方式在5秒请求中慢了约400ms,且速度差异随请求时长增大而更明显。即使加载JSON文件,差异依然存在。排除缓存因素后,fetch()仍有约90%的情况更快。请问为何通过fetch获取资源、创建Object URL再设置iframe的src,比直接设置src指向资源更快?
测试代码
JavaScript
const iframe = document.getElementById("iframe"); const testUri = "https://hacker-news.firebaseio.com/v0/topstories.json"; const fastestEl = document.getElementById('fastest') async function runTests() { const srcTime = await measureLoadTimeUsingSrc() const fetchTime = await measureLoadTimeUsingFetch() document.getElementById("srcTime").textContent = srcTime; document.getElementById("fetchTime").textContent = fetchTime; if (srcTime < fetchTime) { fastestEl.textContent = 'src' } else if (fetchTime < srcTime) { fastestEl.textContent = 'fetch' } else { fastestEl.textContent = 'tie' } } function measureLoadTimeUsingSrc() { return new Promise((resolve, reject) => { const startTime = performance.now() iframe.src = testUri; iframe.addEventListener( "load", () => resolve(performance.now() - startTime), { once: true } ); }); } function measureLoadTimeUsingFetch() { return new Promise((resolve, reject) => { const startTime = performance.now() fetch(testUri) .then((result) => result.blob()) .then((blob) => { iframe.src = URL.createObjectURL(blob); iframe.addEventListener( "load", () => resolve(performance.now() - startTime), { once: true } ); }) .finally(() => URL.revokeObjectURL(iframe.src)); }); }
HTML
<dl> <dt>Time using <code>iframe.src = '…'</code><dt> <dd id="srcTime">…</dd> <dt>Time using <code>fetch('…')</code><dt> <dd id="fetchTime">…</dd> <dt>Fastest</dt> <dd id="fastest">…</dd> </dl> <iframe id="iframe" hidden></iframe> <button type="button" onclick="runTests()"> Run tests </button>
原因分析
- 资源加载阶段的拆分优化:直接设置
iframe.src时,浏览器需要同时处理iframe上下文初始化、URL解析、网络请求、资源接收与渲染,这些步骤存在串行或部分阻塞的情况。而用fetch先获取资源时,网络请求和资源下载在主页面上下文提前完成,后续仅需将本地Blob通过Object URL传给iframe,iframe只需读取本地资源完成加载,省去了自身发起网络请求的链路开销,请求耗时越长,这种提前下载的优势越显著。 - 浏览上下文初始化的开销差异:iframe作为独立的浏览上下文,直接设置
src时,浏览器需要为其初始化安全沙箱、DOM解析器等完整环境,同时并行处理网络请求,两者的资源调度存在冲突。而先通过fetch拿到资源后,iframe的初始化与本地资源加载的重叠度更高,整体耗时更短。 - 请求调度的优先级差异:
fetch请求由主页面直接发起,任务调度优先级更高;而iframe发起的请求属于子上下文任务,调度顺序可能滞后于主上下文任务,导致整体启动延迟。 - 缓存与校验逻辑的隐性区别:即使排除了常规缓存,iframe的请求可能会额外触发安全校验、缓存验证等步骤,而
fetch请求的逻辑更直接,下载完成后转为本地Blob,完全避免了后续的网络相关校验操作。
内容的提问来源于stack exchange,提问作者tvanc
相关产品推荐
相关产品推荐

