Promise非同期関数が順次実行する4つの方法


先日、プログラム問題に遭遇しました.プロミセの順番をコントロールするように要求しました.今日はこれをまとめました.少なくとも四つの方法が実現できます.プロミセの入れ子を含めて、一つのプロミセを通して串刺しにして、プロミセ、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.resoveは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メソッドは配列から次のタスクを取り出して実行します.
三.ゲナート関数
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();
  });
}
この方法を使うには、mergPromiseを修正する方法が必要です.
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();
}
以上の四つの方法を示しましたが、具体的にその方法を使うのも好みによって決められています.他にいい方法があれば、メッセージを補充してください.