async/await未等待执行?Cloudinary图片上传状态更新异常求助
问题:Cloudinary图片上传后React状态提前更新
我基于Cloudinary开发图片上传功能,传入的数组包含已上传的图片URL和未上传的base64格式图片,示例数组如下:
["https://res.cloudinary.com/[userName]/image/upload/v167xxxx4/luxxxfsgasxxxxxx7t9.jpg", "https://res.cloudinary.com/doeejabc9/image/upload/v1675361225/rf6adyht6jfx10vuzjva.jpg", "data:image/jpeg;base64,/9j/4AAUSkZJRgABAQEBLAEsAA.......", "data:image/jpeg;base64,/9j/4AAUSkZJRgABAQEBLAEsAA......."]
我编写了异步函数uploadImage,用于上传未上传的图片并返回全部已上传的URL数组:
export async function uploadImage(el: string[]) { const partition = el.reduce( (result: string[][], element: string) => { element.includes("data:image/") ? result[0].push(element) : result[1].push(element); return result; }, [[], []] ); for (let i = 0; i < partition[0].length; i++) { const data = new FormData(); data.append("file", partition[0][i]); data.append("upload_preset", "my_preset_name"); const res = await fetch( "https://api.cloudinary.com/v1_1/userName/image/upload", { method: "POST", body: data, } ); const file = await res.json(); partition[1].push(file.secure_url); console.log(partition[1]); } return partition[1]; }
之后我通过以下代码调用该函数,期望获取结果后更新React状态并调用API更新数据库:
const uploaded = await uploadImage(el[1]) console.log(uploaded); setFinalVersionDoc({ ...chosenDocument, [chosenDocument[el[0]]]: uploaded, });
但实际情况是状态总是在console.log(uploaded)执行前就更新了,我原本以为async/await会确保获取到值后再执行后续逻辑,现在需要实现上传完成后再更新状态。代码位于项目的component/document文件夹下的EditModal中。
问题排查与解决
1. 核心原因:调用uploadImage的函数未声明为异步
async/await的生效前提是所在函数本身是异步函数。如果调用uploadImage的代码块(比如事件处理函数、useEffect回调)不是异步函数,await会失效,代码会跳过等待直接执行状态更新。
2. 修复步骤
(1)确保调用函数为异步
如果是在事件处理函数中:
const handleConfirm = async () => { const uploaded = await uploadImage(el[1]); console.log(uploaded); setFinalVersionDoc({ ...chosenDocument, [chosenDocument[el[0]]]: uploaded, }); // 在这里调用更新数据库的API };
如果是在useEffect中,需在内部声明异步函数:
useEffect(() => { const updateAfterUpload = async () => { const uploaded = await uploadImage(el[1]); setFinalVersionDoc({ ...chosenDocument, [chosenDocument[el[0]]]: uploaded, }); }; updateAfterUpload(); }, [el, chosenDocument]);
(2)优化uploadImage函数稳定性
- 加入错误处理,避免单张图片上传失败导致流程中断
- 改用
Promise.all并行上传,提升上传效率:
export async function uploadImage(el: string[]) { const [base64List, existingUrls] = el.reduce( ([pending, done], item) => { item.includes("data:image/") ? pending.push(item) : done.push(item); return [pending, done]; }, [[], []] as string[][] ); const uploadTasks = base64List.map(async (base64) => { const formData = new FormData(); formData.append("file", base64); formData.append("upload_preset", "my_preset_name"); const res = await fetch("https://api.cloudinary.com/v1_1/userName/image/upload", { method: "POST", body: formData, }); if (!res.ok) throw new Error(`上传失败:${res.status}`); const result = await res.json(); return result.secure_url; }); try { const newUrls = await Promise.all(uploadTasks); return [...existingUrls, ...newUrls]; } catch (err) { console.error("图片上传出错:", err); throw err; // 抛出错误让调用方处理 } }
(3)验证状态更新时机
可以通过日志顺序确认流程是否正确:
const handleConfirm = async () => { console.log("开始上传图片"); const uploaded = await uploadImage(el[1]); console.log("上传完成,结果:", uploaded); setFinalVersionDoc(prev => ({ ...prev, [chosenDocument[el[0]]]: uploaded, })); };
内容的提问来源于stack exchange,提问作者Antzc
相关产品推荐
相关产品推荐

