Recently I was creating a print button for a report. I wanted the print button to use the PDF version of the report for cross-browser consistency. At first I fetch()
ed the PDF, got the blob, created an object URL, and set the iframes src
property to that URL.
Later I realized I could just set the iframe`s src to the PDF URL in the first place. But that turned out to be slower by ~400ms on a 5s request. In fact the speed difference seems to scale with the length of the request.
Even when just loading a JSON file, as in the snippet below, the speed difference persists.
Here’s a codepen where you can fiddle with the tests yourself. I tried re-arranging and adding cache-busting query-string parameter to eliminate. But fetch()
is still faster ~90% of the time.
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));
});
}
<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>