对于异步方法依次调用,promise提供了链式调用的方法解决了会调地狱的问题,但是如何实现未知异步方法数量的依次调用或者异步方法很多,代码量很大,所以封装一个方法也很有必要。下面结合一道面试题来探讨一下。
实现 mergePromise 函数,把传进去的数组按顺序先后执行,并且把返回的数据先后放到数组 data 中。
题目来源:https://juejin.im/post/5bd697cfe51d454c791cd1d5
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;
});
const mergePromise = ajaxArray => {
// 在这里实现你的代码
};
mergePromise([ajax1, ajax2, ajax3]).then(data => {
console.log('done');
console.log(data); // data 为 [1, 2, 3]
});
方案1(我实现的):
利用对列,递归
const mergePromise2 = ajaxArray => {
let data=[];
//依次从队列中取出任务执行,直至任务对列为0
let m=(resolve)=> Promise.resolve(ajaxArray.length>0?(ajaxArray.shift())():true).then((res)=>{
//执行完毕
if(res===true){
resolve(data)
}
else{
//递归
data.push(res);
m(resolve);
}
})
//返回一个promise对象
return new Promise((resolve,reject)=>{
m(resolve);
})
};
mergePromise([ajax1,ajax2,ajax3]).then(res=>{
console.log('返回的结果');
console.log(res); //[1,2,3]
})
方案2(借鉴的,更简单经典):
利用Promise.resolve链式调用
Promise.resolve方法调用时不带参数,直接返回一个resolved状态的 Promise 对象。
const mergePromise = ajaxArray => {
// 保存数组中的函数执行后的结果
var data = [];
var sequence = Promise.resolve();
ajaxArray.forEach(function (item) {
//每一次循环都是给 sequence 添加链 最后得到的还是promise 的链式调用,只是这个链式调用是动态生成的
sequence = sequence.then(item).then(function (res) {
data.push(res);
return data;
});
})
return sequence;
};
mergePromise([ajax1,ajax2,ajax3]).then(res=>{
console.log('返回的结果');
console.log(res);
})