前幾天遇到一個編程題,要求控制promise順序執行,今天總結了一下這個至少有好四種方法均可以實現,包括promise嵌套,經過一個promise串起來,generator,async實現,如下逐一介紹。 原題目以下:ajax
//實現mergePromise函數,把傳進去的數組順序前後執行,
//而且把返回的數據前後放到數組data中
const timeout = ms => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, ms);
});
const ajax1 = () => timeout(2000).then(() => {
console.log('1');
return 1;
});
const ajax2 = () => timeout(1000).then(() => {
console.log('2');
return 2;
});
const ajax3 = () => timeout(2000).then(() => {
console.log('3');
return 3;
});
function mergePromise(ajaxArray) {
//todo 補全函數
}
mergePromise([ajax1, ajax2, ajax3]).then(data => {
console.log('done');
console.log(data); // data 爲 [1, 2, 3]
});
// 分別輸出
// 1
// 2
// 3
// done
// [1, 2, 3]
複製代碼
function mergePromise1(ajaxArray) {
let arr = [];
return ajaxArray[0]().then(data=>{
arr.push(data);
return ajaxArray[1]();
}).then(data=>{
arr.push(data);
return ajaxArray[2]();
}).then(data=>{
arr.push(data);
return arr;
});
}
複製代碼
function mergePromise2(ajaxArray) {
let p = Promise.resolve();
let arr = [];
ajaxArray.forEach(promise => {
p = p.then(promise).then((data) => {
arr.push(data);
return arr;
});
});
return p;
}
複製代碼
此方法相對於上面的方法簡單而且書寫直觀易懂,還有一種相似的任務隊列,將數組按順序從左邊頭部取出一個執行,執行完成後觸發自定義next方法,next方法負責從數組中取出下一個任務執行。編程
var mergePromise3 = function* (ajaxArray) {
let p1 = yield ajaxArray[0]();
let p2 = yield ajaxArray[1]();
let p3 = yield ajaxArray[2]();
return Promise.resolve([p1,p2,p3]);
}
//自動運行的run
function run(fn) {
return new Promise((resolve, reject) => {
var g = fn;
let arr = [];
function next(preData) {
if(preData) { //若是有數據則push進數組
arr.push(preData);
}
let result = g.next(preData); //獲取每一步執行結果,其中value爲promise對象,done表示是否執行完成
if (result.done) { //函數執行完畢則resolve數組
resolve(arr);
}
else { //函數沒有執行完畢則遞歸執行
result.value.then(function(nowData) {
next(nowData);
});
}
}
next();
});
}
複製代碼
使用這種方法須要修改mergePromise方法爲:數組
run(mergePromise3([ajax1, ajax2, ajax3])).then(data => {
console.log('done');
console.log(data); // data 爲 [1, 2, 3]
});
複製代碼
const co = require('co')
co(mergePromise3([ajax1, ajax2, ajax3])).then(data => {
console.log('done');
console.log(data); // data 爲 [1, 2, 3]
});
複製代碼
此方法原理和上面同樣,只是使用已有的封裝好的co模塊來自動執行promise
function mergePromise4(ajaxArray) {
let arr = [];
async function run() {
for(let p of ajaxArray) {
let val = await p();
arr.push(val);
}
return arr;
}
return run();
}
複製代碼
以上列出了四種方法,具體使用那種方法也根據喜愛而定,若是有其餘的好的方法歡迎留言補充。bash