promise順序執行,返回結果存放在數組


遇到面試的一個編程題:三個返回promise對象的異步操作,讓你寫一個函數可以將這些操作順序執行,並返回一個數組包含三個異步對象的結果

異步對象:

// 異步函數a
var a = function () {
  return new Promise(function (resolve, reject) {
      console.log("a")
    setTimeout(function () {
      resolve('a')
    }, 1000)
  })
}

// 異步函數b
var b = function () {
  return new Promise(function (resolve, reject) {
      console.log("b")
    resolve('b')
  })
}

// 異步函數c
var c = function () {
  return new Promise(function (resolve, reject) {
      console.log("c")
    setTimeout(function () {
      resolve('c')
    }, 500)
  })
}

注意:promise對象在實例化的時候就會執行,所以函數都是返回promise對象,這樣執行函數的時候就會執行promise對象中的內容

我們期望的結果是:

//a
//b
//c
//(3) ["a", "b", "c"]
//done

所以關鍵是怎么順序執行promise並把結果一個一個塞到數組里

注意promise對象是不能直接得到resolve傳來的結果的,一般的方式是.then里面寫resolve的回調函數,所以剛才的需求可以這樣寫

var mergePromise = async function mergePromise(arr) {
    var mergedAjax = Promise.resolve()
    var data = [] ;
    for(let promise of arr){
        mergedAjax = mergedAjax.then(()=>{
            return promise().then(val=>{
                data.push(val)
            })
        })
    }
    return mergedAjax.then(()=>{
        return data
    })
};

mergePromise([a,b,c]).then(function (data) {
    console.log(data);
    console.log("done");
});

還有這種寫法:

var mergePromise = async function mergePromise(arr) {
    var mergedAjax = Promise.resolve()
    var data = [] ;
    for(let promise of arr){
        mergedAjax = mergedAjax.then((val)=>{
            if(val)data.push(val)
            return promise()
        })
    }
    return mergedAjax.then((val)=>{
        data.push(val)
        return data
    })
};

mergePromise(ajaxArray).then(function (data) {
    console.log(data);
    console.log("done");
});

以上兩種其實是一個then的鏈式調用,最后返回收集了異步結果的數組

 

這個需求用asnyc await的寫法就比較好看和直觀

async function queue(arr) {
  let data = []
  for (let promise of arr) {
    let res = await promise()
    data.push(res)
  }
  return data
}
queue([a, b, c])
  .then(data => {
    console.log(data)
console.log("done");
});

感覺上是返回了一個data數組,應該會報沒有.then方法的錯誤,然而實際上是返回了一個Promise.resolve(data)

至於為什么能將resolve的值抽離出來,是應為await是generator的語法糖,比如一個asnyc函數:

async function myfn(arr) {
let res = await a()
console.log(res)
res = await b()
console.log(res)
res = await c()
console.log(res)
}

 
         

myfn([a,b,c])

其實等價於自動執行的generator函數

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {

      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
          //Promise.resolve(next.value)中next.value是一個promise對象,比如a()生成的
          //Promise.resolve(arg)中arg是一個promise對象時,將會原封不動返回這個對象
        step(function() { return gen.next(v); });//這里gen.next(v)執行賦值操作 let res = v 也就是為什么async方法能得到promise中resolve的值
        
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}

function fn(args) {
  return spawn(function* () {
    let res = yield a()
    console.log(res)
    res = yield b()
    console.log(res)
    res = yield c()
    console.log(res)
  });
}

fn()

 

最后說一下,如果要讓異步操作並發,可以用promise自帶的all方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM