기술나눔

프런트 엔드가 동시 요청을 제어하는 ​​방법

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

프런트 엔드는 언제 동시 요청을 제어해야 합니까? 필요한 데이터를 요청하는 데 여러 번 걸리는 경우 예를 들어, 인터페이스가 한 번에 많은 데이터를 반환하는 경우 브라우저가 렌더링에 멈추거나 심지어 충돌할 수도 있습니다. 이때 우리는 멈추거나 충돌하는 것을 방지하기 위해 동시에 6개의 요청을 일괄 전송할 수 있습니다.

그렇다면 프런트 엔드는 동시 요청을 어떻게 제어합니까?

동시 요청의 프런트엔드 제어를 위한 주요 아이디어

예를 들어 요청이 20개라면 다음을 따라야 합니다. 3 첫 번째 그룹이 요청을 완료한 후 두 번째 그룹이 요청되는 방식으로 진행됩니다.

핵심 아이디어는 요청 메소드와 요청 매개변수를 배열에 저장한 후 한 번에 3개를 요청하고 요청이 완료된 후 다음 3개를 요청하는 것입니다. 각 요청 그룹이 반환된 후 결과가 저장되고, 모든 요청이 반환된 후 모든 결과가 반환됩니다.

API 디자인

pControl : 동시 요청 컨트롤러, 최대 동시성 수를 전달합니다.
add : 요청 및 매개변수를 추가합니다.
start : 요청 시작, 약속 반환, 요청 완료 후 통과.then 모든 결과를 얻으십시오.

암호

function pControl(limit) {
  const taskQueue = [] // {task: Function, params: any[]}[]
  return {
    add,
    start
  }

  function add(task, params) {
    taskQueue.push({
      task,
      params
    })
  }

  function start() {
    return runAllTasks()
  }

  function runAllTasks() {
    const allResults = []
    return new Promise((resolve) => {

      runTask()

      function runTask() {
        if (taskQueue.length === 0) {
          // 递归结束
          return resolve(allResults)
        }
        const needRunSize = Math.min(taskQueue.length, limit)
        const tasks = taskQueue.splice(0, needRunSize)
        const promises = tasks.map(({
          task,
          params
        }) => task(params))
        Promise.all(promises).then((resList) => {
          allResults.push(...resList)
          // NOTE 递归调用的位置很关键
          runTask()
        })
      }
    })
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

키 코드 해석

  • pControl: 이 함수는 다음을 포함하는 객체를 반환합니다. add 그리고start 두 가지 방법,add 작업 및 매개변수를 추가하는 데 사용됩니다.start 요청을 시작하는 데 사용되며 폐쇄입니다.

  • runAllTasks:를 반환합니다.promise, 그런 다음new Promise내부적으로 재귀적으로 실행됨runTask, runTask 통과Promise.all 동시 요청 실행Promise.all().then() 다시 전화하세요runTask, 반환할 요청 세트 하나를 구현한 다음 두 번째 요청 세트를 실행합니다.

그룹 기다림을 실현하는 열쇠는 .then 재귀 호출.

생각: 루프를 사용하여 runAllTasks를 구현할 수 있습니까?

응, 사용해야 해 async 和 for 循环 + await

async function runAllTasks2() {
  const allResults = []
  const groupArr = []
  let startIndex = 0
  // 划分分组
  while (startIndex < taskQueue.length) {
    const arr = taskQueue.slice(startIndex, startIndex + limit)
    groupArr.push(arr)
    startIndex += limit
  }
  for (let index = 0; index < groupArr.length; index++) {
    const pList = groupArr[index].map(({
      task,
      params
    }) => task(params))
    const res = await Promise.all(pList)
    allResults.push(...res)
  }
  return allResults
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

for 루프에서는 사용할 수 없습니다 .then 그렇지 않으면 다음 루프는 이전 루프를 기다리지 않습니다.

사용 for of 반복적 구현:

async function runAllTasks2() {
  const allResults = []
  const groupArr = []
  let startIndex = 0
  // 划分分组
  while (startIndex < taskQueue.length) {
    const arr = taskQueue.slice(startIndex, startIndex + limit)
    groupArr.push(arr)
    startIndex += limit
  }
  // 迭代分组
  const it = groupArr.entries()
  for (const [key, value] of it) {
    const pList = value.map(({
      task,
      params
    }) => task(params))
    const res = await Promise.all(pList)
    allResults.push(...res)
  }
  return allResults
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

루프와 약속을 함께 사용하는 방법은 무엇입니까?

forwhilefor...of 명령형 루프 구조의 경우 루프에서 대기 효과를 얻으려면 다음을 사용해야 합니다.async 루프의 함수 래퍼await ,서비스 중단.then

forEachmapfilter 이와 같은 기능 루프 구조는 대기 효과를 지원하지 않습니다. 왜냐하면 이러한 기능 루프 구조는 동기식이고 대기를 지원하지 않기 때문입니다.

async 그리고循环 + await 루프 간 대기 효과를 얻기 위해 결합됩니다.

promise.then 그리고递归 루프 간 대기 효과를 얻기 위해 결합됩니다.

더 쉽게 사용할 수 있도록 API를 개선하세요.

  1. 기본 매개변수 설정: givepControl적절한 기본값을 설정하고 다음으로 설정하십시오.6, 동일한 도메인 이름이 있으므로 브라우저의 동시 요청은 6입니다.
  2. 콜백 시작: 콜백을 통해 각 그룹의 요청 결과를 얻을 수 있으며 현재 완료된 요청 수를 알 수 있습니다.

이 두 가지 개선 사항은 간단합니다. 먼저 사용법을 살펴보겠습니다.

const asyncTaskControl = pControl() // 默认 6 
asyncTaskControl.add(task, params1)
asyncTaskControl.add(task, params2)
// ...
asyncTaskControl.add(task, params10)

asyncTaskControl.start((res, doneSize) => {
  // 获取每组请求的结果 和当前完成了多少请求
  console.log(res) // [{index:number,result:data}] 
  console.log(doneSize)
}).then(allResults => {
  // 所有请求结果
  console.log(allResults)
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

시작 콜백은 무엇을 합니까?

사용자는 현재 동시 요청의 결과를 가져오고 완료 진행률을 계산하는 것이 편리합니다.

위의 함수를 다음과 같이 캡슐화합니다. p-control npm 패키지 출시

npm: p-제어

얻기 쉬운 npm i p-control 다운로드하여 사용하세요.

요약

  • .then 재귀와 결합하여 비동기 작업 간 대기를 달성합니다.
  • forwhile루프를 기다리고async + await비동기 작업 간 대기를 달성하기 위해 조합하여 사용됩니다.
  • 사용Promise.all동시에 실행할 여러 비동기 작업을 구현합니다.