我有一个图像URL数组,我想在网页上按照它们在数组中相应URL的位置顺序显示这些图像。
例如,我们有
const imgUrls = [
"https://picsum.photos/400/400",
"https://picsum.photos/200/200",
"https://picsum.photos/300/300"
];
在这种情况下,我们希望先显示400/400
,然后是200/200
,最后是300/300
。
如果我们天真地实现它,那么顺序就不能保证了。
function loadImages(imgUrls, root) {
imgUrls.forEach((url) => {
const image = document.createElement("img");
image.onload = () => {
root.append(image);
};
image.src = url;
});
}
所以我使用promise来管理异步流控制
async function loadImagesInOrder(imgUrls, rootEl) {
const promises = imgUrls.map(
(url) =>
new Promise((resolve, reject) => {
const image = document.createElement("img");
image.onload = resolve;
image.onerror = reject;
image.src = url;
})
);
for (const p of promises) {
const { currentTarget } = await p;
rootEl.append(currentTarget);
}
}
它可以工作,但不是所有的时间。有了这个实现,有时一些图像将是null
,所以你最终在网页上的null
。
这是一个现场演示https://codesandbox.io/s/load-images-in-order-t16hs?file=/src/index.js
谁能指出问题是什么?还有有没有更好的方法来确保图像出现在页面上的顺序在数组中的URL ?由于某些原因,看起来事件的.currentTarget
有时是null
。一个简单的解决方法是用图像本身来解决Promise,而不是通过有问题的load
处理程序。Keith在评论中找到了原因:
备注:event的值。当前目标只在事件被处理时可用
但是当你这样做的时候
for (const p of promises) {
const { currentTarget } = await p;
rootEl.append(currentTarget);
}
所有图像的加载过程都是立即启动的,但是它们是异步加载的,而且它们通常不会按顺序加载。.currentTarget
将不存在,如果Promise在图片已经加载之后才被解析——例如,如果图片1加载了,那么图片3加载了,然后图片2加载了,那么图片3将在第三张图片
const { currentTarget } = await p;
。
如果您只需要在最后对图像进行适当的排序,那么更简单的方法是立即附加它们。
const root = document.querySelector("#app");
const imgUrls = [
"https://picsum.photos/400/400",
"https://picsum.photos/200/200",
"https://picsum.photos/300/300"
];
for (const src of imgUrls) {
root.appendChild(document.createElement('img')).src = src;
}
<div id="app">