es7的async/await概念已经存在了相当长的时间。具体的概念和用法这里不再赘述。层嵌套回调的问题让代码更简洁明了。本文这里说的是在批量上传多张图片的时候,如果不批量上传,可能会触发浏览器的并发限制,或者图片太多太大上传超时,影响成功图片上传速率。因此,当我们需要批量上传图片时,async/await的概念可以很好的解决我们的问题。否则只能用递归来处理,或者只允许单次上传影响用户体验。其实整个代码和react没有任何关系,只是用到了一些特性,可以适用于任何框架。至于批量获取图片的组件,我直接用了react-dropzone,可以拖放图片。当然,使用原生的也是完全可以的。预览代码//处理获取的图片handleDropFiles=(acceptedFiles)=>{const{maxCount,//最大上传图片数量限制}=this.props;让{selectedFilesTotalSize,selectedFiles}=this.state;const_selectedFiles_=selectedFiles。地图(项目=>项目。文件);//获取成功的图片constsuccessFiles=[],//获取成功的图片rejectedFiles=[],//获取失败的图片existFiles=[];//已经存在if(acceptedFiles&&acceptedFiles.length){for(constfileofacceptedFiles){if(limit*1024this.isSameFile(file,acceptedFile));//通过文件名和文件大小判断是否是同一个文件if(index>=0){existFiles.push(file);}else{successFiles.push(文件);}}}}//如果有不满足条件的图片,输出错误信息lettoastMessage='';if(existFiles.length){constexistFilesName=existFiles.map(item=>`"${item.name}"`);toastMessage=`${existFilesName.join(',')}等文件已经存在;`;}if(rejectedFiles.length){constrejectedFilesName=rejectedFiles.map(item=>`"${item.name}"`);toastMessage=`${toastMessage}${rejectedFilesName.join(',')}等文件不符合上传条件;`;}constincrementLength=successFiles.length;constselectedFilesLength=selectedFiles.length;如果(incrementLength+selectedFilesLength>maxCount){constoverflowFiles=successFiles.splice(maxCount-selectedFilesLength);constoverflowFilesName=overflowFiles.map(item=>`"${item.name}"`);toastMessage=`${toastMessage}${overflowFilesName.join(',')}等文件超过上传数量限制;`;toastMessage&&this.props.onError(toastMessage);//多图预览如果只需要使用云服务上传url预览,可以用handleUploadFiles代替这一步代码if(incrementLength){//这里我选择了createObjectURL而不是readAsDataURL。具体区别不明。如果你想使用readAsDataURL,你必须Promise.allfor(constfileofsuccessFiles){constdataUrl=URL.createObjectURL(file);选定的文件。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;常量{选择ectedFiles,uploadedFiles}=this.state;constchunkFiles=chunkFile(selectedFiles.map(file=>['beforeUpload','failed'].includes(file.uploadStatus)));//未上传或上传失败根据batchCount&batchLimitconstrate=chunkFiles.length;for(const[index,chunkFile]ofchunkFiles.entries()){toast.show(`图片上传${~~(index+1)/rate*100}%`,'loading',this.timeout);//这是一个假图片上传速率constuploadFilePromise=chunkFile.map(this.uploadFile);awaitPromise.all(uploadFilePromise).then((uploadFiles)=>{for(constfileofuploadFiles){if('error'initem){selectedFiles.find(item=>item.index===file.index).uploadStatus='failed';//如果上传失败,改变selectedFiles中的图片状态}else{uploadedFiles.push({url:file.url});}}});this.setState({selectedFiles,uploadedFiles});this.props.onSuccess(上传Fi莱斯);}toast.hide();//组上传函数chunkFile(files){letarray=[],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);}});返回数组;}}上传图片//Ajax上传单张图片,用简单的FormDatauploadFile=(file,index)=>{returnnewPromise((resolve,reject)=>{constformData=newFormData();formData.append('file',file);$.ajax(...,(data)=>{data=(data&&data.data)||{};resolve({url:data.url,index});},(错误)=>{//this.props.onError(err&&err.errMsg||'上传失败');//这里可以根据需要提示有多少张图片上传失败resolve({error:err,index})},this);});}