概述
实际开发中,有时候会接触到多个异步任务串联执行,就是当前一个异步任务处理完毕,然后再接着调用第二个异步任务接着处理,直到所有异步任务执行完毕,这里总结几种常见的解决方案。
具体方案
首先我们需要准备几个需要异步执行的逻辑代码,异步代码我们通过promise来做
// 异步任务1:
function asyncRequestOne() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("asyncRequestOne")
}, 3000)
})
}
// 异步任务2:
function asyncRequestTwo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("asyncRequestTwo")
}, 3000)
})
}
// 异步任务3:
function asyncRequestThree() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("asyncRequestThree")
}, 3000)
})
}
方法1:回调函数
这种事最原始的方式,在promise没有之前,解决异步任务的方式主要为这种方式,容易造成回调地狱
//上面示例移除promis
function getRequest() {
setTimeout(() => { //第一层
console.log('asyncRequestOne');
setTimeout(() => { //第二程
console.log('asyncRequestTwo');
setTimeout(() => { //第三层
console.log('asyncRequestThree');
}, 3000)
}, 1000)
}, 2000)
}
getRequest()
方法1:利用async await
async function getRequest() {
let requestDataRequestOne = await asyncRequestOne();
let requestDataRequestTwo = await asyncRequestTwo();
let requestDataRequestThree = await asyncRequestThree();
console.log([requestDataRequestOne, requestDataRequestTwo, requestDataRequestThree]) //['asyncRequestOne','asyncRequestTwo','asyncRequestThree']
}
getRequest()
方法2:借助Pormise的链式调用
这种实现方式其实也是axios源码中拦截器的实现方,本质上面还是Promise的链式调用的效果,中间可以加上一些自己错误处理也可以
function getRequest() {
let arr = [asyncRequestOne, asyncRequestTwo, asyncRequestThree];
let p = Promise.resolve();
while (arr.length) {
let currentRequest = arr.shift();
p = p.then(currentRequest);
}
}
getRequest();
方法4:promise.all
Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个Promise实例,那个输入的所有 promise 的 resolve 回调的结果是一个数组。
function getRequest() {
let p = Promise.all([asyncRequestOne(), asyncRequestTwo(), asyncRequestThree()]).then((res) => {
console.log(res)//['asyncRequestOne', 'asyncRequestTwo', 'asyncRequestThree']
})
}
getRequest()
总结
本质上,解决异步的执行顺序问题依然是回调函数,只不过promise包装了一层,我们看起来变得更加优雅而已,第二种方法和第三种方法也是本质一样的,await的结果其实就是上次promise成功的值,可以看成第二个方法是第三个方法的语法糖形式。