当前位置: 首页 > article >正文

前端解决页面请求大规模并发问题

前端限制请求的并发数量,可以使用Promise.all来实现,但是Promise.all会等待所有的请求都完成后才会返回,这样会导致页面加载时间过长,所以我们可以使用Promise.race来限制请求的并发数量,当达到限制数量时,后面的请求会等待前面的请求完成后再执行。

具体实现如下:

  1. 定义一个请求队列,用来存储所有的请求。
  2. 定义一个并发数量,用来限制请求的并发数量。
  3. 定义一个函数,用来发送请求,并将请求添加到请求队列中。
  4. 定义一个函数,用来发送请求队列中的请求。
  5. 在发送请求的函数中,判断请求队列的长度是否小于并发数量,如果小于则发送请求,否则等待请求完成后再发送请求。
  6. 在请求完成后,从请求队列中移除该请求。
  7. 在请求完成后,判断请求队列是否还有请求,如果有则继续发送请求。
  8. 在请求完成后,判断请求队列是否为空,如果为空则表示所有请求都已完成。
  9. 在请求完成后,返回请求的结果。
  10. 在发送请求队列中的请求函数中,判断请求队列是否为空,如果为空则返回所有请求的结果。
class RequestQueue {
  constructor(maxConcurrent) {
    this.maxConcurrent = maxConcurrent; // 最大并发请求数
    this.currentConcurrent = 0; // 当前并发请求数
    this.queue = []; // 请求队列

    this.processQueue(); // 开始处理队列
  }

  add(request) {
    return new Promise((resolve, reject) => {
      this.queue.push({ request, resolve, reject });
      this.processQueue(); // 处理队列
    });
  }

  processQueue() {
    // 当前并发请求数小于最大并发请求数,并且队列中还有请求,则从队列中取出请求并执行
    while (
      this.currentConcurrent < this.maxConcurrent &&
      this.queue.length > 0
    ) {
      const { request, resolve, reject } = this.queue.shift();
      this.currentConcurrent++;

      request()
        .then((response) => {
          resolve(response);
        })
        .catch((error) => {
          reject(error);
        })
        .finally(() => {
          this.currentConcurrent--;
          this.processQueue(); // 处理队列
        });
    }
  }
}
// 示例请求函数
function fetchData(url) {
  return fetch(url).then((response) => response.json());
}

// 使用请求队列
const requestQueue = new RequestQueue(5); // 设定最大并发请求数为5
const urls = [
  "https://api.example.com/data1",
  "https://api.example.com/data2",
  "https://api.example.com/data3",
  "https://api.example.com/data4",
  "https://api.example.com/data5",
  "https://api.example.com/data6",
  "https://api.example.com/data7",
  "https://api.example.com/data8",
  "https://api.example.com/data9",
  "https://api.example.com/data10",
]; // 假设我们有10个请求需要发送
const requests = urls.map((url) => () => fetchData(url)); // 将请求函数放入数组中

// // 将请求函数添加到请求队列中
// requests.forEach((request) => {
//   requestQueue.add(request); // 添加请求到队列中
// });
// // 处理队列
// requestQueue.processQueue();

// 使用 Promise.all() 等待所有请求完成
// Promise.all() 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
Promise.all(requests.map((request) => requestQueue.add(request)))
  .then((responses) => {
    console.log(responses);
    console.log("所有请求完成", responses);
  })
  .catch((error) => {
    console.error(error);
    console.log("请求失败", error);
  });

防抖、节流

  1. 防抖函数用于防止函数短时间内多次触发,只有当触发间隔大于指定时间间隔时才会执行函数。常用于输入框搜索、窗口大小调整等场景。
  2. 节流函数用于限制函数在一定时间间隔内只能执行一次,常用于滚动事件、窗口大小调整等场景。
  3. 防抖函数和节流函数都是通过 setTimeout 来实现的,区别在于防抖函数会清除计时器,而节流函数会设置一个计时器。
  4. 防抖函数会在最后一次触发后等待指定时间后执行函数,而节流函数会在第一次触发后立即执行函数。
  5. 防抖函数适用于只需要执行一次的场景,而节流函数适用于需要多次执行的场景。
  // 防抖函数
function debounce(func, wait) {
  let timeout;
  return function () {
    const context = this;
    const args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(context, args);
    }, wait);
  };
}
// 节流函数
function throttle(func, wait) {
  let timeout;
  return function () {
    const context = this;
    const args = arguments;
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null;
        func.apply(context, args);
      }, wait);
    }
  };
}
// 防抖函数的使用
const handleSearch = debounce(() => {
  // 处理搜索逻辑
})
// 输入框输入事件
// inputElement.addEventListener('input', handleSearch);


// 节流函数的使用
const handleScroll = throttle(() => {
  // 处理滚动逻辑
  console.log('handleScroll');
})
// 滚动事件
window.addEventListener('scroll', handleScroll);
// 注意:节流函数需要手动清除计时器,否则会导致无法再次触发。
// clearTimeout(timeout); // 清除计时器


// vue中防抖函数和节流函数的使用
// 在vue中,我们可以将防抖函数和节流函数封装成全局方法,然后在组件中使用。
// 在main.js中封装防抖函数和节流函数 (也可以直接在组件中import引入函数来使用)
Vue.prototype.$debounce = debounce;
Vue.prototype.$throttle = throttle;
// 在组件中使用
export default {
  methods: {
    handleSearch() {
      // 处理搜索逻辑
    }
  },
  mounted() {
    // 输入框输入事件
    this.$debounce(this.handleSearch, 300);
  }
}

http://www.kler.cn/a/589960.html

相关文章:

  • Linux 如何上传本地文件以及下载文件到本地命令总结
  • CAD-随缘:CAD导出PDF 与 PDF导入成CAD
  • 猎豹移动(Cheetah Mobile)
  • LeetCode hot 100 每日一题(10)——56. 合并区间
  • 【VSCode】VSCode常用插件
  • 合成复用原则
  • 云原生函数计算:无服务器架构的基因重组
  • Flask+Vue-Router+JWT实现登录验证
  • [网络] socket编程--udp_echo_server
  • 【自学笔记】Redis基础知识点总览-持续更新
  • 在本地跑通spark环境
  • 程序化广告行业(22/89):腾讯广告业务布局与广告效果评估基础
  • 无再暴露源站!群联AI云防护IP隐匿方案+防绕过实战
  • coding ability 展开第四幕(滑动指针——巩固篇)超详细!!!!
  • 【华为OD-E卷 - 字符统计及重排 100分(python、java、c++、js、c)】
  • jmeter 循环控制器遍历列表中的数据
  • 20250317笔记本电脑在ubuntu22.04下使用acpi命令查看电池电量
  • test skills
  • 【数据分析】数据筛选与访问行列元素3
  • 2020年蓝桥杯第十一届CC++大学B组(第二次)真题及代码