Promise異步函數順序執行的四種方法

前幾天遇到一個編程題,要求控制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]

一. promise嵌套

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;
    });
}

二. Promise.resolve將promise串連成一個任務隊列

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

三. generator函數

1. 原生generator函數

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]
});

2. 利用co模塊自動執行

const co = require('co')
  co(mergePromise3([ajax1, ajax2, ajax3])).then(data => {
  console.log('done');
  console.log(data); // data 爲 [1, 2, 3]
});

此方法原理和上面同樣,只是使用已有的封裝好的co模塊來自動執行編程

四. async函數

function mergePromise4(ajaxArray) {
  let arr = [];
  async function run() {
      for(let p of ajaxArray) {
          let val = await p();
          arr.push(val);
      }
      return arr;
  }
  return run();
}

以上列出了四種方法,具體使用那種方法也根據喜愛而定,若是有其餘的好的方法歡迎留言補充。數組

相關文章
相關標籤/搜索