我有一个简单的表格,可以进行文件上传。
<form @submit.prevent="sendForm" enctype="multipart/form-data">
<input multiple ref="PostFiles" name="PostFiles" type="file" @change="selectFile('add')">
<!-- other fields here -->
<button type="submit" name="Send" value="Send"></button>
</form>
selectFile()
方法调用uploadFile()
方法,以使用axios.post()
请求将用户选择的文件发送到服务器。 await
需要selectFile()
才能完成
提交之前。这是selectFile()
的工作,可以正常工作。等待uploadFile()
解决,然后在所有上传完成后在控制台中收到成功消息:
async selectFile(action) {
if (action === 'add') {
// It adds the files to the array this.Form.PostFiles
let PostFiles = this.$refs.PostFiles.files;
if (this.Form.PostFiles == null || this.Form.PostFiles.length === 0) {
this.Form.PostFiles = [...this.Form.PostFiles, ...PostFiles].map(file => { //returns a new array with the file object and metainfo object
return [
file, {
originalFilename: file.name,
uploadedFilename: "",
size: file.size,
type: file.type,
isUploading: false,
isUploaded: false,
uploadProgress: 0,
previewImgSrc: URL.createObjectURL(file)
}
]
});
} else {
PostFiles = Array.from(PostFiles).map(file => {
return [
file, {
originalFilename: file.name,
uploadedFilename: "",
size: file.size,
type: file.type,
isUploading: false,
isUploaded: false,
uploadProgress: 0,
previewImgSrc: URL.createObjectURL(file)
}
]
});
this.Form.PostFiles.push(...PostFiles);
}
}
try {
return Promise.all(
this.Form.PostFiles.map(async (file, i) => {
const File = file[0];
if (this.Form.PostFiles[i][1].isUploaded == false &&
this.Form.PostFiles[i][1].isUploading == false) {
await this.uploadFile({File: File, FileIndex: i});
}
})
)
.then(result => {
console.log("Successfully uploaded all files")
}).catch(err => {
console.log(err)
})
} catch (err) {
console.log(err)
}
}
uploadFile()
方法使用axios
上传文件,如下所示:
async uploadFile({ File, FileIndex }) {
const FormFile = new FormData();
FormFile.append("UploadFile", File);
this.Form.PostFiles[FileIndex][1].isUploading = true;
return this.$axios.post('/api/post', FormFile)
.then(response => {
this.Form.PostFiles[FileIndex][1].isUploading = false;
this.Form.PostFiles[FileIndex][1].isUploaded = true;
}).catch(err => {
console.log(err)
})
因此,这里是发生问题的地方。如果在上传仍在进行时用户点击了表单的“提交”按钮,则sendForm()
方法不会等待selectFile()
来解决所有承诺,然后再提交文件:
async sendForm() {
const FormBody = new FormData();
FormBody.append("PostTitle", this.Form.PostTitle);
FormBody.append("PostDescription", this.Form.PostDescription);
try {
await this.selectFile();
this.$axios.post('/api/post', FormBody).then(response => {
console.log("Form submitted");
}).catch(err => {
console.log(err.response.data.error)
})
} catch (error) {
console.log(error);
}
}
我在控制台中收到一条消息,提示“表单已提交”,尽管可能仍在进行3次上传。似乎在第一次上传完成后立即打印“表单已提交”。为什么不等待selectFile()
?如何解决此问题,以便它在提交表单之前等待所有文件完成上传?
答案 0 :(得分:1)
在@change="selectFile('add')"
上,将文件添加到this.$refs.PostFiles
并启动上载。现在您正在this.Form.PostFiles[FileIndex][1].isUploading = true;
进行上传。 this.Form.PostFiles.map(async (file, i) => { … }
保留axios
返回的承诺。因此,一旦所有文件上传完毕,您就可以正确看到Successfully uploaded all files
。
对于sendForm
,您再次调用selectFile
,这部分代码将再次执行:
return Promise.all(
this.Form.PostFiles.map(async (file, i) => {
const File = file[0];
if (this.Form.PostFiles[i][1].isUploaded == false &&
this.Form.PostFiles[i][1].isUploading == false) {
await this.uploadFile({File: File, FileIndex: i});
}
})
)
.then(result => {
console.log("Successfully uploaded all files")
}).catch(err => {
console.log(err)
})
但是现在所有文件的this.Form.PostFiles[i][1].isUploading
是true
。因此,您的代码基本上就是这样的:
return Promise.all(
this.Form.PostFiles.map(async (file, i) => {
const File = file[0];
})
)
.then(result => {
console.log("Successfully uploaded all files")
}).catch(err => {
console.log(err)
})
因此Promise.all
可以“立即”解决,而不是等待上传文件完成。 Successfully uploaded all files
被记录两次(如果您在提交表单后不重新加载页面),并且如果现在在两次记录之间进行记录,则您只会看到一次,并且前面有一个显示2
的标志。
您可以做的是保存公理返回的Promise,并将其保存在存储isUploading
的对象中,并在代码的else
分支中使用它,以防上载到进度或完成:
return Promise.all(
this.Form.PostFiles.map(async (file, i) => {
const File = file[0];
if (this.Form.PostFiles[i][1].isUploaded == false &&
this.Form.PostFiles[i][1].isUploading == false) {
this.Form.PostFiles[i][1].uploadPromise = this.uploadFile({File: File, FileIndex: i});
await this.Form.PostFiles[i][1].uploadPromise;
} else {
await this.Form.PostFiles[i][1].uploadPromise;
}
})
)
.then(result => {
console.log("Successfully uploaded all files")
}).catch(err => {
console.log(err)
})
虽然这可以解决问题,但将它们组合成一个函数仍然不是一种好方法,因为名称selectFile
对于在submitForm
情况下的行为具有极大的误导性情况。
答案 1 :(得分:-1)
我认为您必须将promise从uploadFile返回到映射数组:
return Promise.all(
this.Form.PostFiles.map(async (file, i) => {
const File = file[0];
return await this.uploadFile({
File: File
});
})
)
.then(result => {
console.log("Successfully uploaded all files")
}).catch(err => {
console.log(err)
})
} catch (err) {
console.log(err)
}
答案 2 :(得分:-3)
尽管这不能回答您的特定问题,但是您可以在上传正在进行时禁用表单提交按钮,还可以在提交表单之前检查是否正在进行任何上传。