廈門網(wǎng)站開發(fā)網(wǎng)站建設(shè)網(wǎng)站目前病毒的最新情況
微信小程序多圖片上傳實(shí)用代碼記錄
由于在小程序中,wx.uploadFile 只能一次上傳一張圖片,因此在一次需要上傳多張圖片的應(yīng)用場(chǎng)景中例如商品圖片上傳、評(píng)論圖片上傳等場(chǎng)景下,不得不使用for等循環(huán)上傳每一張圖片,多次調(diào)用wx.uploadFile,由此引發(fā)了ajax的閉包問題。
初始代碼
submit() {let tmparr = null;let _that = this;for (var k = 0; k < this.data.judgedetaillist.length; k++) {let _k = k;//圖片上傳this.data.fileList[_k].forEach((item) => { wx.uploadFile({ //這里一定要用 wx.uploadFile 否則無法穿到后臺(tái)filePath: item.url, //你要上傳的路徑name: 'file', //你上傳到后臺(tái)的name值async: false, //設(shè)置為同步formData:{ // 如果你要驗(yàn)證你的token 可以用formData來給后臺(tái)傳值path:"judge"},url: 上傳地址,success(res){let img = JSON.parse(res.data); //錄入到listif(img.err=='success' && img.c_url!=null && img.c_url!=undefined){if(_that.data.judgedetaillist[_k].fileList.length==0 || _that.data.judgedetaillist[_k].fileList==null || _that.data.judgedetaillist[_k].fileList==undefined){_that.data.judgedetaillist[_k].fileList=[];}_that.data.judgedetaillist[_k].fileList.push({url:img.c_url});_that.setData({judgedetaillist:_that.data.judgedetaillist})}}})})}console.log(JSON.stringify(this.data.judgedetaillist));return false;}
代碼問題
我這代碼的設(shè)想是,
遍歷儲(chǔ)存上傳文件的 fileList數(shù)組-》wx.uploadFile上傳到服務(wù)器-》返回服務(wù)器路徑-》將返回的路徑傳送到 judgedetaillist.fileList中-》judgedetaillist傳輸?shù)胶笈_(tái)新增評(píng)論
這個(gè)代碼執(zhí)行下來會(huì)出現(xiàn)問題,即在 wx.uploadFile后獲取了對(duì)應(yīng)的url存儲(chǔ)到j(luò)udgedetaillist中后
console.log(JSON.stringify(this.data.judgedetaillist));
會(huì)出現(xiàn)
fileList":[]
但是
如果打印
console.log(this.data.judgedetaillist);
會(huì)出現(xiàn)
fileList: Array(1)
0:
url: “/upload/judge/16654684.png”
proto: Object
length: 1
nv_length: (…)
proto: Array(0)
在預(yù)設(shè)的對(duì)象中又能讀取到數(shù)據(jù),此時(shí)再打印
console.log(this.data.judgedetaillist[0].fileList.length);
發(fā)現(xiàn)明明數(shù)組中有對(duì)象,但是這個(gè)對(duì)象根本取不到,并且連length都無法讀取
原因剖析
由于wx.uploadFile默認(rèn)是使用異步,因此在不斷的for循環(huán)中,它返回的值并不是同步的,導(dǎo)致多個(gè)同時(shí)執(zhí)行,此時(shí)數(shù)組使用的是地址引用,并沒有實(shí)際賦值成功,賦值的數(shù)組已經(jīng)被修改了,因?yàn)樵瓉淼拈L(zhǎng)度是0,所以獲取不到數(shù)組,但又包含修改后的結(jié)果。
要解決這個(gè)bug就是讓wx.uploadFile可以同步執(zhí)行,需要用到
1、new Promise
2、async,await
3、取消forEach, forEach 中使用 async/await 時(shí),異步操作并不會(huì)等待前一個(gè)操作結(jié)束再執(zhí)行下一個(gè),而是會(huì)同時(shí)執(zhí)行多個(gè)異步操作
解決方案(非生產(chǎn)環(huán)境代碼)
本來h5中的多圖片上傳是直接使用 async:false就可以,但是在微信中這是無效的。所以代碼寫成這樣
解決方案一
使用new Promise,配合async,await進(jìn)行多次循環(huán)
//圖片上傳函數(shù)
Upload: function (uploadFile) {return new Promise((resolve, reject) => {wx.uploadFile({ //這里一定要用 wx.uploadFile 否則無法穿到后臺(tái)filePath: uploadFile, //你要上傳的路徑name: 'file', //你上傳到后臺(tái)的name值formData: { // 如果你要驗(yàn)證你的token 可以用formData來給后臺(tái)傳值path: "judge"},url: 上傳路徑,success: (res) => {// 上傳完成操作const data = JSON.parse(res.data)resolve({data: data})},fail: (err) => {//上傳失敗:修改pedding為rejectwx.showToast({title: "網(wǎng)絡(luò)出錯(cuò),上傳失敗",icon: 'none',duration: 1000});reject(err)}});})},//接收返回的路徑,關(guān)鍵是async ,await
async submit() {let tmparr = null;for (var k = 0; k < this.data.judgedetaillist.length; k++) {let _k = k;//圖片上傳for (let i = 0; i < this.data.fileList[_k].length; i++) {tmparr =await this.Upload(this.data.fileList[_k][i].url);if(this.data.judgedetaillist[_k].fileList==null || this.data.judgedetaillist[_k].fileList==undefined){this.data.judgedetaillist[_k].fileList=[];}this.data.judgedetaillist[_k].fileList.push({ url: tmparr.data.c_url });this.setData({judgedetaillist: this.data.judgedetaillist})}}console.log(JSON.stringify(this.data.judgedetaillist));
}
解決方案二
利用Promise.all,當(dāng)所有的異步請(qǐng)求成功后才會(huì)執(zhí)行,將全部異步執(zhí)行完后的數(shù)據(jù)一次性返回
調(diào)用測(cè)試
console.log(this.uploadImage(this.data.fileList[_k]))
返回結(jié)果
Promise {}
proto: Promise
[[PromiseState]]: “fulfilled”
[[PromiseResult]]: Array(3)
0: “/upload/judge/1691391628202skmda.png”
1: “/upload/judge/1691391628219ttxps.png”
2: “/upload/judge/1691391628227yehwf.png”
length: 3
nv_length: (…)
proto: Array(0)
利用這個(gè)可以一次性獲取全部的結(jié)果
代碼示例:
uploadImage: function(tempFilePaths){return new Promise((presolve,preject)=>{if({}.toString.call(tempFilePaths)!='[object Array]'){throw new TypeError(`上傳圖片參數(shù) tempFilePaths 類型錯(cuò)誤!`)}//路徑數(shù)組為空時(shí) 不上傳if(tempFilePaths.length==0){presolve([])return}let uploads = []tempFilePaths.forEach((item,i)=>{uploads[i] = new Promise ((resolve)=>{console.log(item);wx.uploadFile({ //這里一定要用 wx.uploadFile 否則無法穿到后臺(tái)filePath: item.url, //你要上傳的路徑name: 'file', //你上傳到后臺(tái)的name值formData: { // 如果你要驗(yàn)證你的token 可以用formData來給后臺(tái)傳值path: "judge"},url: 你的上傳路徑,success(res){console.log(res);resolve(JSON.parse(res.data).c_url)},fail(err){console.log(err)}})})})Promise.all(uploads).then(res=>{//圖片上傳完成presolve(res)}).catch(err=>{preject(err)wx.showToast({title:'上傳失敗請(qǐng)重試',icon:'none'})})})},