JavaScript:使用Promises按顺序加载图片时的奇怪bug



我有一个图像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">

相关内容

  • 没有找到相关文章

最新更新