遇到面试的一个编程题:三个返回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方法