小程式使用 Promise.all 完成檔案非同步上傳

Kindear發表於2021-04-23

小程式使用 Promise.all 完成檔案非同步上傳

extends [微信小程式開發技巧總結(二) -- 檔案的選取、移動、上傳和下載 - Kindear - 部落格園 (cnblogs.com)]

在上述文章中我們提到了兩種檔案上傳的方式:

  1. 使用for迴圈遍歷

    優點:接近併發上傳,上傳速度較快

    缺點:無法保證返回結果的順序

  2. 採用遞迴方式上傳

    優點:保證了檔案的返回順序和上傳順序一致,且對伺服器負載更小

    缺點:由於同步順序執行上傳過程,耗費時間過長

那麼有沒有一種方式可以讓上傳非同步執行並且保證返回的順序呢?

魚與熊掌可以兼得,這波啊,這波不虧

這就引入本篇文章的主角 Promse.all非同步並行機制了

關於Promise的兩種機制,我就不再贅述,請看參考文件

專案結構

|--upload
     |--upload.js
     |--upload.json
     |--upload.wxml
     |--upload.wxss
     |--profunc.js

本文以雲開發圖片上傳舉例

程式碼展示

profunc.js

const cloudpath = 'baseimg';
function CloudUploadImage(path) {
  // 本地檔案路徑
  return new Promise(function (resolve, reject) {
    wx.getFileInfo({
      filePath: path,
      success(ans) {
        wx.cloud.uploadFile({
          cloudPath: cloudpath + '/' + ans.digest + '.png',
          filePath: path,
          success: res => {
            resolve(res)
          },
          fail(res) {
            reject('upload fail')
          }
        })
      }
    })
  })
}
module.exports={
  CloudUploadImage:CloudUploadImage
}

upload.js

// pages/upload/upload.js
const cwx = require('profunc.js');
Page({

  /**
   * 頁面的初始資料
   */
  data: {
    imgList:[]
  },
  UploadImage(){
    let imglist = this.data.imgList;
    var promisetasks = []
    for(var i=0;i<imglist.length;i++){
      promisetasks.push(cwx.CloudUploadImage(imglist[i]))
    }
    wx.showLoading({
      title:'圖片上傳中'
    })
    Promise.all(promisetasks).then(res=>{
      
      console.log(res)
      //具體處理寫在如下
    })
  },
  ChooseImage() {
    wx.chooseImage({
      count: 4, //預設9
      sizeType: ['original', 'compressed'], //可以指定是原圖還是壓縮圖,預設二者都有
      sourceType: ['album'], //從相簿選擇
      success: (res) => {
        if (this.data.imgList.length != 0) {
          this.setData({
            imgList: this.data.imgList.concat(res.tempFilePaths)
          })
        } else {
          this.setData({
            imgList: res.tempFilePaths
          })
        }
      }
    });
  },
  ViewImage(e) {
    wx.previewImage({
      urls: this.data.imgList,
      current: e.currentTarget.dataset.url
    });
  },
  DelImg(e) {
    this.data.imgList.splice(e.currentTarget.dataset.index, 1);
    this.setData({
      imgList: this.data.imgList
    })
  },
  /**
   * 生命週期函式--監聽頁面載入
   */
  onLoad: function (options) {

  },

  /**
   * 生命週期函式--監聽頁面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命週期函式--監聽頁面顯示
   */
  onShow: function () {

  },

  /**
   * 生命週期函式--監聽頁面隱藏
   */
  onHide: function () {

  },

  /**
   * 生命週期函式--監聽頁面解除安裝
   */
  onUnload: function () {

  },

  /**
   * 頁面相關事件處理函式--監聽使用者下拉動作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 頁面上拉觸底事件的處理函式
   */
  onReachBottom: function () {

  },

  /**
   * 使用者點選右上角分享
   */
  onShareAppMessage: function () {

  }
})

upload.wxml

<view class="cu-bar bg-white margin-top">
		<view class="action">
			圖片上傳
		</view>
		<view class="action">
			{{imgList.length}}/4
		</view>
	</view>
	<view class="cu-form-group">
		<view class="grid col-4 grid-square flex-sub">
			<view class="bg-img" wx:for="{{imgList}}" wx:key="index" bindtap="ViewImage" data-url="{{imgList[index]}}">
				<image src='{{imgList[index]}}' mode='aspectFill'></image>
				<view class="cu-tag bg-red" catchtap="DelImg" data-index="{{index}}">
					<text class="cuIcon-close"></text>
				</view>
			</view>
			<view class="solids" bindtap="ChooseImage" wx:if="{{imgList.length<4}}">
				<text class="cuIcon-cameraadd"></text>
			</view>
		</view>
	</view>

  <view class="padding flex flex-direction">
  <button class="cu-btn bg-green lg" bindtap="UploadImage">上傳</button>
  <!-- <button class="cu-btn bg-red margin-tb-sm lg">嫣紅</button> -->
</view>

upload.wxss

使用了colorui樣式元件,請參考參考文件下載

/* pages/upload/upload.wxss */
@import '/colorui/main.wxss';

參考文件

1. Color Ui | 極其鮮亮的高飽和色彩,更注重視覺的小程式元件庫 (color-ui.com)

2.理解和使用Promise.all和Promise.race - 簡書 (jianshu.com)

相關文章