一、前言
最近在做小程式的開發,碰到的一個需求就是表單提交,提交的表單中包含有圖片,微信這邊的做法是先上傳圖片,後臺把圖片名稱和地址返回給你,然後你把圖片資訊插入到表單的相應位置再提交表單,這裡就涉及到如何上傳完圖片的請求再上傳表單,而且微信小程式裡面如果圖片是多個的話,也只能一張張上傳。簡單來說就是上傳完圖片(多個請求),拿到返回值,再上傳表單,該如何做?
二、Promise.all和Promise.race
先來介紹Promise.all和Promise.race方法的不同點
Promise.all(iterable)
方法指當所有在可迭代引數中的 promises 已完成,或者第一個傳遞的 promise(指 reject)失敗時,返回 promise。iterable為可迭代物件,但是一般為陣列。返回值也是一個Promise物件。
需要明確的幾點,Promise.all是併發執行的同時執行多個Promise物件,而且返回的Promise物件的引數是一個陣列,陣列中的各項也是可迭代物件執行的順序返回。
Promise.race(iterable)
方法返回一個新的 promise,引數iterable中只要有一個promise物件”完成(resolve)”或”失敗(reject)”,新的promise就會立刻”完成(resolve)”或者”失敗(reject)”,並獲得之前那個promise物件的返回值或者錯誤原因。所以只要iterable中有一個完成或者失敗就立即返回一個promise物件。根據race這個單詞為賽跑也能得出,最先到達的立即返回一個promise物件。
根據上面的定義,我們採用的Promise.all方法來完成我們的需求。
//儲存promise物件的陣列
let promiseArr = [];
//圖片地址陣列
let imageList = [];
//將圖片地址的上傳的promise物件加入到promiseArr
for (let i = 0; i < imageList.length; i++) {
let promise = new Promise((resolve, reject) => {
//微信圖片上傳
wx.uploadFile({
url: 'https://xxx.xxx.xxx/api/uploadImage',
filePath: imageList[i],
name: 'file',
success: function(res) {
//可以對res進行處理,然後resolve返回
resolve(res);
},
fail: function (error) {
reject(error);
},
complete: function (res) {
},
})
});
promiseArr.push(promise)
}
//Promise.all處理promiseArr陣列中的每一個promise物件
Promise.all(promiseArr).then((result) => {
//對返回的result陣列進行處理
})
複製程式碼
三、微信小程式的問題
在做微信小程式的圖片上傳功能,這邊只能先上傳圖片,然後將圖片名和地址以response返回。
這裡面我們就是用了promise.all方法但是有一個問題就是,promise.all是併發執行的,但是微信小程式一次只能併發10個請求。
對於圖片上傳,可能需要一次上傳超過10張圖片,也就是一次併發超過10個請求,這樣的話微信就會報錯
四、順序Promise執行處理
因為Promise.all是同時執行多個promsie物件,所以對於這種併發的數量,小程式是有限制的,一次只能併發10個,所以如果想突破這種限制,可以進行順序執行每個Promise。
程式碼如下:
//順序處理函式
function sequenceTasks(tasks) {
//記錄返回值
function recordValue(results, value) {
results.push(value);
return results;
}
let pushValue = recordValue.bind(null, []);
let promise = Promise.resolve();
// 處理tasks陣列中的每個函式物件
for (let i = 0; i < tasks.length; i++) {
let task = tasks[i];
promise = promise.then(task).then(pushValue);
}
return promise;
}
//函式陣列,每個函式的返回值是一個promise物件
let promiseFuncArr = [];
//圖片地址陣列
let imageList = [];
//將圖片地址的上傳的函式加入到promiseFuncArr陣列中
for (let i = 0; i < imageList.length; i++) {
let promiseTemp = function(){
return new Promise((resolve, reject) => {
//微信圖片上傳
wx.uploadFile({
url: 'https://xxx.xxx.xxx/api/uploadImage',
filePath: imageList[i],
name: 'file',
success: function(res) {
//可以對res進行處理,然後resolve返回
resolve(res);
},
fail: function (error) {
reject(error);
},
complete: function (res) {
},
})
});
};
promiseFuncArr.push(promiseTemp)
}
sequenceTasks(promiseFuncArr).then((result) => {
//對返回的result陣列進行處理
});
複製程式碼
1.這裡解釋一下sequenceTasks函式的作用
首先recordValue函式傳入兩個值,一個是results是返回的陣列,另一個是value,value是傳入的值,results.push(value);將每一個值push到results陣列,然後再返回results陣列。
let pushValue = recordValue.bind(null, []);
pushValue也是一個函式物件,將recordValue bind到一個[ ]陣列中,第一個引數傳null代表,不改變函式this的指向,所以pushValue得到就是一個function (value)的函式,引數傳入value。
promise = promise.then(task).then(pushValue);
task是函式,函式返回promise物件,在我們這裡就是上傳圖片函式,每一張圖片上傳都建立一個函式,then(pushValue),pushValue是function (value)的函式,value代表的就是圖片上傳之後的返回值,pushValue將返回值push到result陣列中,依次執行,依次加入到result陣列中,最後返回。就可以得到一個物件陣列,陣列中就是依次執行返回的結果。
2. sequenceTasks也裡面的for迴圈,也可以寫成如下的reduce方式:
function sequenceTasks(tasks) {
//記錄返回值
function recordValue(results, value) {
results.push(value);
return results;
}
let pushValue = recordValue.bind(null, []);
return tasks.reduce(function (promise, task) {
return promise.then(task).then(pushValue);
}, Promise.resolve());
}
複製程式碼
(來自公眾號:前端八點半)