Promise同时获取n个接口数据的几种方式

先使用Promise封装, 以便使用它的链式调用方法:

const url1 = './data1.json'

const url2 = './data2.json'

const url3 = './data3.json'


const getData = async(url) => {
    return new Promise((resolve, reject)=> {
        axios({
            method: 'get',
            url,
            data: {},
        })
        .then(res=> {
            resolve(res)
        })
        .catch(err=> {
            reject(err)
        })
    })
}

1.链式调用:

getData(url1)
.then(data1 => {
    console.log(data1)
    return getData(url2)
})
.then(data2 => {
    console.log(data2)
    return getData(url3)
})
.then(data3 => {
    console.log(data3)
})
.catch(err => console.log(err));

2. asyc await

const data1 = await getData(url1)
const data2 = await getData(url2)
const data3 = await getData(url3)

console.log(data1, data2, data3)

3.Promise.allSettled

mock数据, 想要成功的数据可以Promise.resolve({a: 1}), mock失败的返回数据: Promise.reject({err1: 1})

const f1 = getData(url1)
const f2 = Promise.reject({err2: 2})
const f3 = Promise.reject({err3: 3})
Promise.allSettled([f1, f2, f3])
.then(res => {
  // 成功和失败的数据都会返回, 可以根据需要筛选需要的数据
  console.log(res, 'allSettled-success')
})
.catch(err => {
  // catch没有catch到接口返回的错误数据, 全部都返回到then去了
  console.log(err, 'error')
})
.finally(() => {
  // 不管成功还是失败都会走到finally
  console.log('finally')
})

4.Promise.all

Promise.all([f1, f2, f3])
.then(res => {
  // 全部都是返回成功的数据才会打印
  console.log(res, 'all-success')
})
.catch(err => {
  // 只要有一个失败就会打印, 剩下的失败就不会打印了
  console.log(err, 'error')
})
.finally(()=> {
  // 不管成功还是失败都会走到finally
  console.log('all--finally')
})

5.Promise.race只有第一个resolve或者reject的数据返回了, 其余的不返回

Promise.race([f1, f2, f3])
.then(res => {
  // 如果第一个返回数据是resolve的, 就打印
  console.log(res, 'race-success')
})
.catch(err => {
  // 如果第一个返回数据reject的, 就打印
  console.log(err, 'race-error')
})
.finally(()=> {
  // 不管第一个返回的是成功还是失败都会走到finally
  console.log('race--finally')
})

6.Promise.all如果想要成功结果和失败结果一起返回,则

function onReject(err) {
  return (err);
}
const f1 = () => getData(url1).catch(onReject)
const f2 = () => getData(url2).catch(onReject)
const f3 = () => getData(url3).catch(onReject)

Promise.all([f1, f2, f3])
.then(res => {
  console.log(res, 'all-success')
})
.catch(err => {
  console.log(err, 'error')
})
.finally(()=> {
  // 不管成功还是失败都会走到finally
  console.log('all--finally')
})

7.Promise和setTimeout模拟并发场景:

function onReject(err) {
  return (err);
}

const f1 = () => getData(url1).catch(onReject)
const f2 = () => getData(url2).catch(onReject)
const f3 = () => getData(url3).catch(onReject)
const f4 = ()=> getData(url4).catch(onReject)
const f5 = () => getData(url5).catch(onReject)
const f11 = () => getData(url11).catch(onReject)
const f12 = () => getData(url12).catch(onReject)
const f13 = () => getData(url13).catch(onReject)
const f14 = ()=> getData(url14).catch(onReject)
const f15 = () => getData(url15).catch(onReject)


/**
 * 代码的核心思路为:

1.先初始化 promiseListLimit 个 promise 实例,将它们放到 executing 数组中
2.使用 Promise.race 等待这 promiseListLimit 个 promise 实例的执行结果
3.一旦某一个 promise 的状态发生变更,就将其从 executing 中删除,然后再执行循环生成新的 promise,放入executing 中
4.重复2、3两个步骤,直到所有的 promise 都被执行完
5.最后使用 Promise.all 返回所有 promise 实例的执行结果
 */
const concurrencyPromisePool = async (
  promiseListLimit,
  promiseArr,
  mockTimeoutDataFn
) => {
  const allPromiseArr = []; // 用于存放所有的promise实例
  const executing = []; // 用于存放目前正在执行的promise
  for (let index = 0; index < promiseArr.length; index++) {
    const promise = promiseArr[index];
    const mockPromise = mockTimeoutDataFn(promise, index); // 回调函数返回的必须是promise,否则需要使用Promise.resolve进行包裹
    allPromiseArr.push(mockPromise);
    if (promiseListLimit <= promiseArr.length) {
      // then回调中,当这个promise状态变为fulfilled后,将其从正在执行的promise列表executing中删除
      const executingItem = mockPromise.then(() =>
        executing.splice(executing.indexOf(executingItem), 1)
      );
      executing.push(executingItem);
      console.log(`并发接口数量: ${executing.length}`);
      if (executing.length >= promiseListLimit) {
        // 一旦正在执行的promise列表数量等于限制数,就使用Promise.race等待某一个promise状态发生变更,
        // 状态变更后,就会执行上面then的回调,将该promise从executing中删除,
        // 然后再进入到下一次for循环,生成新的promise进行补充
        await Promise.race(executing);
      }
    }
  }
  return Promise.all(allPromiseArr);
};

// mock有1s延迟时间的promise, 方便查看并发的效果
const timeout = (promiseFn, i) => {
  console.log("开始--", i);
  return new Promise((resolve) =>
    setTimeout(() => {
      console.log("结束--", i);
      return resolve(promiseFn());
    }, 1000)
  );
};

const getConcurrencyPromise = async () => {
  try {
    const res = await concurrencyPromisePool(
      2,
      [f1, f2, f3, f4, f5, f11, f12, f13, f14, f15],
      timeout
    );
    console.log(res);
  } catch (error) {
    console.log(error, "errrrrr");
  }
};

getConcurrencyPromise();

并发方法可以用于多种场景,比如大文件分片上传,要求并发,每次可以传多片的情形

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`Promise.all` 可以同时接受多个接口数据,它接受一个由多个 `Promise` 实例组成的数组作为参数,返回一个新的 `Promise` 实例,当数组中所有 `Promise` 实例都执行成功时,该实例才会执行成功。其语法如下: ```javascript Promise.all([promise1, promise2, promise3]) .then(([result1, result2, result3]) => { // 所有 Promise 都成功执行的回调函数 }) .catch(error => { // 任意一个 Promise 执行失败的回调函数 }); ``` 其中,`then` 回调函数的参数是一个数组,包含了每个 `Promise` 执行成功后的结果,数组中的顺序与传入 `Promise.all` 的数组顺序相同。如果其中任意一个 `Promise` 执行失败,则会跳过后续的 `Promise`,并执行 `catch` 回调函数。 举个例子,如果我们需要同时请求两个接口数据,并在两个接口数据都返回后对数据进行处理,可以这样实现: ```javascript const promise1 = fetch('/api/data1'); const promise2 = fetch('/api/data2'); Promise.all([promise1, promise2]) .then(([response1, response2]) => { return Promise.all([response1.json(), response2.json()]); }) .then(([data1, data2]) => { // 处理两个接口返回的数据 }) .catch(error => { // 处理异常情况 }); ``` 在上面的例子中,我们使用 `fetch` 函数请求了两个接口数据,并将返回的 `Promise` 实例放入一个数组中传给 `Promise.all`。在 `then` 回调函数中,我们将返回的 `Response` 对象转化为 JSON 数据,并将两个 `Promise` 实例放入一个新的数组中再次调用 `Promise.all`,以等待两个接口数据全部返回。最终我们可以在第二个 `then` 回调函数中使用返回的数据进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值