Berbagi teknologi

Bagaimana front end mengontrol permintaan bersamaan

2024-07-12

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

Kapan front end perlu mengontrol permintaan bersamaan? Kapan diperlukan beberapa kali untuk meminta data yang diperlukan. Misalnya, jika antarmuka mengembalikan data dalam jumlah besar sekaligus, browser akan terjebak dalam rendering atau bahkan crash. Saat ini, kami dapat mengeluarkan 6 permintaan sekaligus secara batch, untuk menghindari stuck atau crash .

Jadi bagaimana front end mengontrol permintaan bersamaan?

Ide-ide kunci untuk kontrol front-end atas permintaan bersamaan

Misalnya ada 20 permintaan, Anda harus mengikuti 3 Setelah kelompok pertama menyelesaikan permintaan, kelompok kedua akan diminta, dan seterusnya.

Ide utamanya adalah menyimpan metode permintaan dan parameter permintaan dalam sebuah array, kemudian meminta 3 sekaligus, dan kemudian meminta 3 berikutnya setelah permintaan selesai. Setelah setiap grup permintaan dikembalikan, hasilnya disimpan, dan setelah semua permintaan dikembalikan, semua hasil dikembalikan.

desain api

pControl : Pengontrol permintaan serentak, melewati jumlah konkurensi maksimum;
add : Tambahkan permintaan dan parameter;
start : Mulai permintaan, kembalikan janji, lewati setelah permintaan selesai.then Dapatkan semua hasil;

Kode

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

Interpretasi kode kunci

  • pControl: Fungsi ini mengembalikan objek yang berisi add Danstart Dua metode,add Digunakan untuk menambahkan tugas dan parameter,start Digunakan untuk memulai permintaan, ini adalah penutupan.

  • runAllTasks: mengembalikan apromise, lalu masuknew PromiseDieksekusi secara internal secara rekursifrunTask, runTask lolosPromise.all Jalankan permintaan bersamaan diPromise.all().then() menelepon lagirunTask, terapkan satu set permintaan untuk dikembalikan, lalu jalankan set permintaan kedua.

Kunci untuk mewujudkan penantian kelompok adalah dengan melakukan .then panggilan rekursif.

Berpikir: Bisakah runAllTasks diimplementasikan menggunakan loop?

Ya, perlu digunakan 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

Tidak dapat digunakan dalam perulangan for .then , jika tidak, loop berikutnya tidak akan menunggu loop sebelumnya.

menggunakan for of Implementasi berulang:

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

Bagaimana cara menggunakan loop dan Promise secara bersamaan?

forwhilefor...of Untuk struktur loop imperatif, jika Anda ingin mencapai efek menunggu dalam loop, Anda harus menggunakanasync pembungkus fungsi dalam loopawait ,Sedang dalam perbaikan.then

forEachmapfilter Struktur loop fungsional seperti ini tidak mendukung efek menunggu, karena struktur loop fungsional ini sinkron dan tidak mendukung menunggu.

async Dan循环 + await Dikombinasikan untuk mencapai efek menunggu antar loop.

promise.then Dan递归 Dikombinasikan untuk mencapai efek menunggu antar loop.

Tingkatkan API agar lebih mudah digunakan

  1. Tetapkan parameter default: berikanpControlTetapkan nilai default yang sesuai, setel ke6, karena nama domain yang sama, permintaan bersamaan browser adalah 6.
  2. mulai menelepon balik: Melalui panggilan balik, Anda bisa mendapatkan hasil permintaan masing-masing grup dan mengetahui jumlah permintaan yang sedang diselesaikan.

Kedua peningkatan ini sederhana. Mari kita lihat penggunaannya terlebih dahulu:

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

Apa fungsi panggilan balik awal?

Akan lebih mudah bagi pengguna untuk mendapatkan hasil permintaan bersamaan saat ini dan menghitung kemajuan penyelesaian.

Enkapsulasi fungsi-fungsi di atas menjadi p-control rilis paket npm

npm: kontrol-p

dapat diakses npm i p-control Unduh dan gunakan.

ringkasan

  • .then Dikombinasikan dengan rekursi untuk mencapai waktu tunggu di antara tugas-tugas asinkron;
  • forwhileTunggu loop danasync + awaitDigunakan dalam kombinasi untuk mencapai waktu tunggu antara tugas-tugas asinkron;
  • menggunakanPromise.allTerapkan beberapa tugas asinkron untuk dijalankan secara bersamaan.