遇到面試的一個編程題:三個返回promise對象的非同步操作,讓你寫一個函數可以將這些操作順序執行,並返回一個數組包含三個非同步對象的結果 非同步對象: 註意:promise對象在實例化的時候就會執行,所以函數都是返回promise對象,這樣執行函數的時候就會執行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方法