javascript - JavaScript:使用 Promises 按顺序加载图像时出现奇怪的错误
问题描述
我有一组图像 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;
});
}
所以我使用 Promises 来管理异步流控制
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
处理程序。基思在评论中找到了原因:
注意: event.currentTarget 的值仅在处理事件时可用
但是当你这样做时
for (const p of promises) {
const { currentTarget } = await p;
rootEl.append(currentTarget);
}
所有图像的加载过程都会立即启动,但它们是异步加载的,并且通常不会按顺序加载。如果 Promise 在图像已经加载后解析,.currentTarget
则不会存在 - 例如,如果图像 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">
推荐阅读
- java - Android导航抽屉点击事件问题
- javascript - 如何通过 JSON 数组中的 Loop 方法检查元素
- xml - 如何使用 PowerShell 在一个元素中获取整个节点?
- python - 如何根据另一列值迭代pandas DataFrame多索引和过滤
- git - 如何删除超出容量限制的文件
- javascript - 在 Windows 上运行 forever.js 时出错 - “'C:\Program' 未被识别为内部或外部命令、可运行程序或批处理文件”
- flutter-web - How to build flutter web app in debug mode?
- java - 片段中的按钮 onClick 中的 NullPointerException
- android - WorkManager - 当我们同时使用默认初始化和自定义初始化时,我们是否应该删除默认初始化程序?
- c++ - 默认/样板代码在 Visual Studio 2017 中给我错误。E1574。虚幻。但是构建成功