axios.all与Promise.all并发请求

前言

在工作中当我们的项目来到一个新的页面需要发多个请求,而这些请求的数据又毫不相干时,我们可以采取并发请求的方式。目前并发请求主要有Promise.all和axios.all两种方式,下面做详细介绍。

Promise.all

Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

1
var p = Promise.all([p1,p2,p3]);

上面代码中,Promise.all 方法接受一个数组作为参数,p1、p2、p3 都是 Promise 对象的实例。(Promise.all 方法的参数不一定是数组,但是必须具有 iterator 接口,且返回的每个成员都是 Promise 实例。)

p 的状态由 p1、p2、p3 决定,分成两种情况

  • (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
  • (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

下面是一个具体的例子

1
2
3
4
5
6
7
8
// 3个函数都是封装的axios,返回promise实例的函数
let reqArr = [getNames(), getTypes(), getAges()]

 Promise.all(reqArr).then((resArr) => {<!-- -->
       console.log('请求结果', resArr)
 })

// 如果3个请求都成功,返回结果是存放3个请求结果的数组

在这里插入图片描述

axios.all

axios.all的用法基本和Promise.all一致,因为axios.all方法就是对Promise.all方法进行了一层包装,本质上是一模一样的,没有任何额外的逻辑,所以调用axios.all方法就是调用了Promise.all方法。

注意:axios.all是axios的静态方法,不是axios实例的方法!可通过在main.js中引入axios,并将其挂载在vue原型上,实现全局使用

1
2
3
4
5
6
let reqArr = [getNames(), getTypes(), getAges()]

axios.all(reqArr).then((resArr) => {<!-- -->
     console.log('请求结果', resArr)
 })
// 返回结果同上

axios.all与Promise.all有区别的地方在于then中对于返回结果的处理,axios除了上面这种用法之外,还可以在then中调用axios.spread函数,axios.spread函数接受一个回调函数,回调函数的参数就是与请求相同顺序和数量的返回结果

1
2
3
4
5
6
7
let reqArr = [getNames(), getTypes(), getAges()]

 axios.all(reqArr).then(axios.spread((first, second, third)=>{<!-- -->
            console.log('结果1', first)
            console.log('结果2', second)
            console.log('结果3', third)
}))

返回结果
在这里插入图片描述
axios.all与Promise.all之间的关系
axios.all方法就是对Promise.all方法进行了一层包装,本质上是一模一样的,没有任何额外的逻辑

  1. axios.all的本质
1
2
3
axios.all = function(promises) {<!-- -->
  return Promise.all(promises);
};
  1. axios.spread的本质
    axios.all方法与Promise.all方法是一模一样的,唯一看起来不同的地方就是then方法,我们先来比较这两个then方法中的内容:
1
2
3
4
5
// axios.all的then
axios.spread((first, second) => {<!-- -->})

// Promise.all的then
([first, second]) => {<!-- -->}

我们可以看到,Promise.all的then方法里面是个函数,函数的参数是所有请求的响应组成的数组;而axios.all的then方法里面调用了axios.spread方法,axios.spread方法接收一个函数作为参数,该参数函数的参数也是所有请求的响应,既然上文说了axios.all方法与Promise.all方法是一模一样的,那么我们只需想办法再让两个then方法相同即可。也就是说我们创建一个axios.spread方法并且让axios.spread((first, second) => {})的返回值与([first, second]) => {}等价即可。

axios.spread的实现

1
2
3
4
5
6
7
8
axios.all = function(promises) {<!-- -->
  return Promise.all(promises);
};
axios.spread = function(callback) {<!-- -->
  return function wrap(arr) {<!-- -->
    return callback.apply(null, arr);
  };
};
并发请求时的错误处理

根据Promise.all的用法我们知道,当参数数组中的所有promise实例都是fulfilled状态时,Promise.all的返回实例才会是fulfilled,否则返回实例的状态就是rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

这也就意味着我们并发的几个请求当中,只要有一个请求出错,就无法返回正常的结果。但我们希望有错误出现时,也能正常返回其他请求成功的结果。我们可以通过为每个请求添加catch错误处理来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let reqArr = [axios({<!-- -->method: 'get', url: 'www.baidu.com'}), getTypes(), getAges()]

// 为每个请求添加错误处理
 let handledErrReqs = reqArr.map(item => item.catch(error => {<!-- -->
        // 错误处理代码
        console.log('请求出错', error)
       
        // 也可以返回你想要的错误提示结果,如果不返回数据,那么获得的值就是undefined
        // return {msg: '请求出错'}
 }))
axios.all(handledErrReqs).then(axios.spread((first, second, third)=>{<!-- -->
        console.log('结果1', first)
        console.log('结果2', second)
        console.log('结果3', third)
 }))

以上方法对axios.all与Promise.all都适用

参考文章:
【异步技术】Axios并发请求
axios添加axios.all和axios.spread方法,与promise.all
并发请求时错误处理
JavaScript Promise 对象