When preloading an image with Javascript, is there a difference between using new Image()
vs document.createElement(link)
with re="preload"
?
E.g., is there a difference between:
const loadImage = (src) =>
new Promise(r => {
const image = new Image()
image.onload = r
image.onerror = r
image.src = src
})
and
const loadImage = (src) =>
new Promise((resolve, reject) => {
const link = document.createElement("link")
link.rel = "preload"
link.as = "image"
link.href = src
link.onload = () => {
document.head.removeChild(link)
resolve(undefined)
}
link.onerror = reject
document.head.appendChild(link)
})
I couldn't notice anything when testing. My use case is I want to load an image before updating the page to avoid a flash as the image loads.
CodePudding user response:
There isn't much difference, but both will only let you know when the network request is finished. That's only one part of the job of the Image.
You'll notice this mostly with big images, but the decoding of the image data can also take a considerable amount of time, and lead to some unpleasant flashes in some browsers.
To be clear, in the load event you already have the width and height of the image, so after that you won't have a weird resizing of the boxes in the pages, but still in some browsers you may have an empty box for quite some time, or even some weird glitches while the image is being decoded, or simply lock the whole page while the decoding is happening.
To avoid that, you can use the HTMLImageElement#decode()
method which will return a Promise resolving when this decoding is done.
Running the below snippets in Firefox you should see the red box before the image actually is displayed in the "onload" case, while in the "decode" case it's displayed directly. In Chrome you should see that the JS interval is blocked for almost a second with "onload", while it's about just a few ms with "decode()":
onload
// a big image
const url = "https://upload.wikimedia.org/wikipedia/commons/c/cf/Black_hole_-_Messier_87.jpg?";
const img = new Image();
img.src = url Math.random();
let i = 0;
// keep something happening on the screen
const elem = document.querySelector("pre");
const timer = setInterval(() => elem.textContent = i , 4);
img.onload = (evt) => {
document.body.append(img);
// stop the loop after some time
setTimeout(() => clearTimeout(timer), 10000);
};
img { background: red; height: 150px }
<pre></pre>
decode()
// a big image
const url = "https://upload.wikimedia.org/wikipedia/commons/c/cf/Black_hole_-_Messier_87.jpg?";
const img = new Image();
img.src = url Math.random();
let i = 0;
// keep something happening on the screen
const elem = document.querySelector("pre");
const timer = setInterval(() => elem.textContent = i , 4);
img.decode().then((evt) => {
document.body.append(img);
// stop the loop after some time
setTimeout(() => clearTimeout(timer), 10000);
});
img { background: red; height: 150px }
<pre></pre>