使用 Javascript 预加载图像时,使用
new Image()
与 document.createElement(link)
与 rel="preload"
之间有区别吗?
例如,以下之间有区别吗:
const loadImage = (src) =>
new Promise(r => {
const image = new Image()
image.onload = r
image.onerror = r
image.src = src
})
和
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)
})
测试时我没有注意到任何事情。我的用例是我想在更新页面之前加载图像,以避免图像加载时出现闪烁。
没有太大区别,但两者只会在网络请求完成时让您知道。这只是图像工作的一部分。
您会在大图像中注意到这一点,但图像数据的解码也可能需要相当长的时间,并导致某些浏览器中出现一些令人不快的闪烁。
需要明确的是,在加载事件中,您已经有了图像的宽度和高度,因此之后您不会对页面中的框进行奇怪的大小调整,但在某些浏览器中,您可能会看到一个空框有时,甚至在解码图像时出现一些奇怪的故障,或者在解码发生时简单地锁定整个页面。
HTMLImageElement#decode()
方法,该方法将在解码完成后返回 Promise 解析。
在 Firefox 中运行以下代码片段,在“onload”情况下,您应该在图像实际显示之前看到红色框,而在“decode”情况下,它会直接显示。在 Chrome 中,您应该看到“onload”时 JS 间隔被阻塞了近一秒,而“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>