提问人:Jay 提问时间:11/5/2023 更新时间:11/5/2023 访问量:49
每次迭代中带有 async/await 的 array.forEach(callback) 是异步的吗?[复制]
Is array.forEach(callback) with async/await inside each iteration asynchronous? [duplicate]
问:
我正在使用 react,我有以下代码:
const [avatarURLs, setAvatarURLs] = useState({});
const [currentTutorProfile, setCurrentTutorProfile] = useState({});
const [avatarURLsLoaded, setAvatarURLsLoaded] = useState(false); // New state
useEffect(() => {
const avatarObject = {};
const fetchAvatar = async (tutorProfile) => {
try {
if (tutorProfile) {
const response = await axios.get(
`${process.env.REACT_APP_BASE_URL}/users/${tutorProfile.owner}/avatar`,
{ responseType: "arraybuffer" }
);
const blob = new Blob([response.data], {
type: "image/png",
});
const imageUrl = URL.createObjectURL(blob);
avatarObject[tutorProfile.owner] = "imageUrl";
}
} catch (error) {
// console.error("Error fetching user avatar:", error);
}
};
tutorProfilesArray.forEach(fetchAvatar);
console.log(avatarObject); // THIS ONE
setAvatarURLs(avatarObject);
setAvatarURLsLoaded(true); // Mark that avatarURLs are loaded
}, [tutorProfilesArray]);
我有一个控制台.log(avatarObject) // 这个,测试avatarObject的行,我得到空对象,然后对象值在一段时间后被填充。
我注意到只有当 api 调用与 await 一起使用时才会出现这种行为(例如:await axios.get())。当在没有 await 的情况下使用 api 调用时(例如:axios.get()),avatarObject 会立即更新。所以这是我不明白的;既然使用了 await,那么即使完成了 api 调用,该行也不应该以顺序(同步)方式执行吗?
这是我几个月来一直在做的副业,我一直在努力解决这个问题一个星期,但无法弄清楚为什么以及如何解决这个问题。如果这恰好是您可能知道解决方案的事情,如果我能听到一些解释,我将不胜感激。
谢谢
我正在尝试的是:遍历一个数组并为数组的每个元素获取个人资料图片,并使用对象将其存储到 react useState 变量中。
问题:它确实将个人资料图片存储到 useState 变量中,但是,它是在一段时间后完成的(我假设),因此当前端最初呈现时,它看不到任何个人资料图片,因此它没有呈现个人资料图片。
答:
是的,也不是。实际上,里面的回调可以是异步的,但语句本身不能。这意味着 将在语句中的回调仍在处理时执行。这就是为什么一开始你会看到一个空对象,但一段时间后你会看到对象被填满的原因。.forEach
forEach
console.log(avatarObject);
forEach
有一些方法可以解决此问题:
1. 与Promise.all
map
该方法的工作方式与方法类似,但区别在于它返回一个新数组,其中包含执行的每个回调的结果,如果是异步回调,则结果将是 Promise。鉴于此,您可以使用该语句等待 中的所有回调完成,然后再继续。如下所示:map
forEach
Promise.all
map
useEffect(() => {
async function fetchUsersAvatarAndUpdateState() {
const avatarObject = {};
await Promise.all(
tutorProfilesArray.map(async (tutorProfile) => {
// ... code
}),
);
console.log(avatarObject); // THIS ONE
setAvatarURLs(avatarObject);
setAvatarURLsLoaded(true); // Mark that avatarURLs are loaded
}
fetchUsersAvatarAndUpdateState();
}, [tutorProfilesArray]);
2.改用for await
该循环是异步的,可用于异步迭代,如下所示:for await (...)
useEffect(() => {
async function fetchUsersAvatarAndUpdateState() {
const avatarObject = {};
for await (const tutorProfile of tutorProfilesArray) {
// ... code
}
console.log(avatarObject); // THIS ONE
setAvatarURLs(avatarObject);
setAvatarURLsLoaded(true); // Mark that avatarURLs are loaded
}
fetchUsersAvatarAndUpdateState();
}, [tutorProfilesArray]);
请注意,这两种解决方案之间存在一些差异。如果你想更深入地了解这一点,我建议阅读这个线程:等待VS Promise.all
评论
array.forEach
使用异步函数很少做你真正想要的 - 除非你想要的是回调函数在后续代码中的已知点绝对没有可用的结果......即是的,异步函数即使在.forEach
response
response.data