前幾天遇到一個編程題,要求控制promise順序執行,今天總結了一下這個至少有好四種方法均可以實現,包括promise嵌套,經過一個promise串起來,generator,async實現,如下逐一介紹。
原題目以下:
//實現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方法負責從數組中取出下一個任務執行。ajax
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模塊來自動執行編程
function mergePromise4(ajaxArray) { let arr = []; async function run() { for(let p of ajaxArray) { let val = await p(); arr.push(val); } return arr; } return run(); }
以上列出了四種方法,具體使用那種方法也根據喜愛而定,若是有其餘的好的方法歡迎留言補充。數組