es7提出的async/await觀點已存在有相稱長一段時間,詳細觀點用法就不在這裏贅述了,上風在於處置懲罰處理then鏈多層嵌套回調的題目,使得代碼更加簡樸清楚。
本文在這裏要講的是批量上傳多張圖片時,假如不分批上傳能夠觸發瀏覽器的併發限定,亦或是圖片過量過大致使上傳超時,都邑影響圖片的上傳勝利率。所以,我們須要分批上傳圖片時,async/await觀點就能夠很好的處理我們的題目。不然,就只能運用遞歸來處置懲罰,或是只允許單張上傳影響用戶體驗。
實在悉數代碼和react沒有太大關聯,只是用到部份特徵,是能夠適用於任何框架的。至於批量獵取圖片的組件我直接用的是react-dropzone,能夠拖拽圖片,固然了,運用原生的
<input type=”file” accept={//圖片範例} multiple/>也是完整OK的。
預覽代碼
//處置懲罰獵取的圖片
handleDropFiles = (acceptedFiles) => {
const {
maxCount, //最多上傳圖片張數
limit
} = this.props;
let { selectedFilesTotalSize, selectedFiles } = this.state;
const _selectedFiles_ = selectedFiles.map(item => item.file); //已勝利獵取過的圖片
const successFiles = [], //獵取勝利的圖片
rejectedFiles = [], //獵取失利的圖片
existFiles = []; //已存在的圖片
if (acceptedFiles && acceptedFiles.length) {
for (const file of acceptedFiles) {
if (limit * 1024 < file.size) {
rejectedFiles.push(file);
} else {
const index = _selectedFiles_.findIndex(acceptedFile => this.isSameFile(file, acceptedFile)); //經由過程文件名文件大小推斷是不是是統一文件
if (index >= 0) {
existFiles.push(file);
} else {
successFiles.push(file);
}
}
}
}
// 如有不符合前提的圖片輸出錯誤信息
let toastMessage = '';
if (existFiles.length) {
const existFilesName = existFiles.map(item => `"${item.name}"`);
toastMessage = `${existFilesName.join(', ')}等文件已存在;</br>`;
}
if (rejectedFiles.length) {
const rejectedFilesName = rejectedFiles.map(item => `"${item.name}"`);
toastMessage = `${toastMessage}${rejectedFilesName.join(', ')}等文件不符合上傳前提;</br>`;
}
const incrementLength = successFiles.length;
const selectedFilesLength = selectedFiles.length;
if (incrementLength + selectedFilesLength > maxCount) {
const overflowFiles = successFiles.splice(maxCount - selectedFilesLength);
const overflowFilesName = overflowFiles.map(item => `"${item.name}"`);
toastMessage = `${toastMessage}${overflowFilesName.join(', ')}等文件超越上傳數目的限定;</br>`;
}
toastMessage && this.props.onError( toastMessage );
// 多圖預覽 假如只須要用雲效勞上傳后的url預覽能夠將此步驟替換為handleUploadFiles的代碼
if (incrementLength) {
// 這裏挑選了createObjectURL而不是readAsDataURL詳細區分不詳說了 假如要用readAsDataURL還得Promise.all一下
for (const file of successFiles) {
const dataUrl = URL.createObjectURL(file);
selectedFiles.push({
file,
name: file.name,
size: file.size,
dataUrl,
uploadStatus: 'beforeUpload' //標識圖片狀況,以後有能夠上傳失利須要從新上傳
});
}
selectedFiles = selectedFiles.map((item, index) => return {...item, {index: index}});
selectedFilesTotalSize = selectedFiles.reduce((previousSize, nextFile) => previousSize + nextFile.size, 0);
this.setState({
selectedFiles,
selectedFilesTotalSize
});
}
}
批量上傳代碼
// 批量上傳獵取的圖片
handleUploadFiles = async () => {
const {
batchCount, //一組最多上傳圖片張數(考慮到瀏覽器併發)
batchLimit //最多上傳一組圖片大小(考慮到瀏覽器上傳速度限定)
} = this.props;
const { selectedFiles, uploadedFiles } = this.state;
const chunkFiles = chunkFile(selectedFiles.map(file => ['beforeUpload', 'failed'].includes(file.uploadStatus))); //依據batchCount&batchLimit給未上傳或上傳失利的圖片組分塊
const rate = chunkFiles.length;
for (const [index, chunkFile] of chunkFiles.entries()) {
toast.show(`圖片上傳中${~~(index+1)/rate*100}%`, 'loading', this.timeout); //這裏做了個假的圖片已上傳率
const uploadFilePromise = chunkFile.map(this.uploadFile);
await Promise.all(uploadFilePromise).then((uploadFiles) => {
for (const file of uploadFiles) {
if ('error' in item) {
selectedFiles.find(item => item.index === file.index).uploadStatus = 'failed'; //若上傳失利變動selectedFiles里的圖片狀況
} else {
uploadedFiles.push({ url: file.url });
}
}
});
this.setState({ selectedFiles, uploadedFiles });
this.props.onSuccess(uploadedFiles);
}
toast.hide();
// 分組上傳
function chunkFile(files) {
let array = [],
subArray = [],
size = 0;
files.forEach((item, index) => {
size += item.size;
if (size > batchLimit*1024 || subArray.length === batchCount) {
array.push(subArray);
subArray = [item];
size = item.size;
} else {
subArray.push(item);
}
if (index === files.length-1) {
array.push(subArray);
}
});
return array;
}
}
上傳圖片
// ajax上傳單張圖片,就是簡樸的FormData隨意看下就好
uploadFile = (file, index) => {
return new Promise((resolve, reject) => {
const formData = new FormData();
formData.append('file', file);
$.ajax(..., (data)=>{
data = (data && data.data) || {};
resolve({ url: data.url, index });
}, (err) => {
//this.props.onError(err && err.errMsg || '上傳失利'); //能夠在這依據需求提醒第幾張圖片上傳失利
resolve({ error: err, index })
}, this);
});
}