React+Redux项目Async/Await执行顺序异常:外部代码先于异步函数运行
问题整理
概述
我正在开发一个使用Redux的React应用,有一个action负责检查是否存在新的imageData,若存在则将其上传,获取返回的新URL后,使用该数据更新对象。
问题描述
异步函数内部的执行顺序符合预期,但函数外部的代码会在异步函数执行完成前就运行。
疑问
为什么底部的console log会在我写的异步函数内容全部执行完成前就触发?
相关代码:
if(imageData) { const imageGUID = guid(); const storageRef = projectStorage.ref(`${imageData.name}_${imageGUID}`); // 该函数应当在底部的console log调用前执行完成 await storageRef.put(imageData).on('state_changed', snap => { }, async (err) => { console.log(err) toastr.error("Uh Oh!", `Could not upload image`); }, async () => { imageURL = await storageRef.getDownloadURL(); console.log("NEW IMAGE URL: ", imageURL); }) } console.log("Done setting up new image: ", imageURL) // 该行代码在从Firestore获取IMAGE URL前就被调用,原因是什么?
解答
问题根因
storageRef.put(imageData).on() 方法返回的不是Promise对象,你在它前面加的await没有实际作用,代码不会等待回调逻辑执行完成就会往下走。
Firebase的on()是事件监听模式,你传入的第三个参数是上传完成后的成功回调函数,这个回调是异步触发的,不属于当前await能捕获的异步执行链,因此后续的console.log会先执行。
修复方案
将整个上传逻辑包装成标准Promise,手动控制resolve/reject的时机,这样await就能正常等待整个上传+获取URL的流程执行完成:
if(imageData) { const imageGUID = guid(); const storageRef = projectStorage.ref(`${imageData.name}_${imageGUID}`); // 包装为Promise让await生效 imageURL = await new Promise((resolve, reject) => { storageRef.put(imageData).on('state_changed', snap => {}, err => { console.log(err) toastr.error("Uh Oh!", `Could not upload image`); reject(err) }, async () => { const url = await storageRef.getDownloadURL(); console.log("NEW IMAGE URL: ", url); resolve(url) } ) }) } console.log("Done setting up new image: ", imageURL)
修改后await会等待Promise内部的上传、获取URL全部执行完成后才会向下执行,底部的log就能拿到正确的imageURL了。
内容的提问来源于stack exchange,提问作者Bromox
相关产品推荐
相关产品推荐

