欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端如何控制并發(fā)請求舉例詳解

 更新時間:2024年09月01日 14:42:05   作者:JackChouMine  
在項目中我們會遇到一次請求多個接口,當(dāng)所有請求結(jié)束后進(jìn)行操作,也會遇到多個請求(大量)同時進(jìn)行請求資源,這篇文章主要給大家介紹了關(guān)于前端如何控制并發(fā)請求舉例的相關(guān)資料,需要的朋友可以參考下

前言

什么情況需要前端控制并發(fā)請求,在需要多次才能請求完所需數(shù)據(jù)的時候。比如接口一次返回,數(shù)據(jù)很多,讓瀏覽器渲染卡頓甚至崩潰,這時候我們可以分批同時發(fā)出6個請求,這樣就可以避免卡頓或者崩潰。

那么前端如何控制并發(fā)請求呢?

前端控制并發(fā)請求的關(guān)鍵思路

比如有 20 個請求,需要按照 3 個一組,第一組請求完畢后再請求第二組,以此類推。

關(guān)鍵思路,把請求方法和請求參數(shù)使用一個數(shù)組存起來,然后每次請求3個,請求完畢后再請求下一個3個。每組請求返回后,把結(jié)果保存起來,等所有請求都返回后,再把所有結(jié)果返回。

api 設(shè)計

  • pControl : 并發(fā)請求控制器, 傳遞最大并發(fā)數(shù);
  • add : 添加請求和參數(shù);
  • start : 開始請求,返回promise, 請求完畢后通過 .then 獲取所有結(jié)果;

代碼實現(xiàn)

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) {
          // 遞歸結(jié)束
          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 遞歸調(diào)用的位置很關(guān)鍵
          runTask()
        })
      }
    })
  }
}

關(guān)鍵代碼解讀

  • pControl: 這個函數(shù)返回一個對象,包含 add 和 start 兩個方法,add 用來添加任務(wù)和參數(shù),start 用來開始請求,是一個閉包。

  • runAllTasks: 返回一個promise,然后在new Promise內(nèi)部遞歸地執(zhí)行runTask, runTask 通過Promise.all 執(zhí)行并發(fā)請求,在Promise.all().then() 再次調(diào)用runTask,實現(xiàn)一組請求返回,再執(zhí)行第二組請求。

實現(xiàn)分組等待的關(guān)鍵是在 .then 中遞歸調(diào)用。

思考: runAllTasks 可以使用循環(huán)實現(xiàn)嗎?

能,需要使用 async 和 for 循環(huán) + 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
}

在 for 中循環(huán)中不能使用 .then ,否則下一次循環(huán)不會等待上一次循環(huán)。

使用 for of 迭代實現(xiàn):

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
}

循環(huán)和 Promise 結(jié)合是怎樣使用的呢?

for 、 while 、 for...of 等命令式循環(huán)結(jié)構(gòu),想要在循環(huán)中實現(xiàn)等待效果,必須使用 async 函數(shù)包裹循環(huán)中的 await ,不能使用 .then 。

forEach 、 map 、 filter 等函數(shù)式循環(huán)結(jié)構(gòu),不支持等待效果,因為這些函數(shù)式循環(huán)結(jié)構(gòu)是同步的,不支持等待。

async 和 循環(huán) + await 結(jié)合,實現(xiàn)循環(huán)之間等待效果。

promise.then 和 遞歸 結(jié)合,實現(xiàn)循環(huán)之間等待效果。

完善 api,讓其更加易用

  • 設(shè)置默認(rèn)參數(shù):給pControl設(shè)置一個合適的默認(rèn)值,設(shè)置為6,因為同一個域名在,瀏覽器的并發(fā)請求是 6 個。
  • start給回調(diào):通過回調(diào)能拿到每個分組的請求結(jié)果和知道當(dāng)前完成的請求數(shù)量。

這兩個改進(jìn)很簡單。先看用法:

const asyncTaskControl = pControl() // 默認(rèn) 6 
asyncTaskControl.add(task, params1)
asyncTaskControl.add(task, params2)
// ...
asyncTaskControl.add(task, params10)

asyncTaskControl.start((res, doneSize) => {
  // 獲取每組請求的結(jié)果 和當(dāng)前完成了多少請求
  console.log(res) // [{index:number,result:data}] 
  console.log(doneSize)
}).then(allResults => {
  // 所有請求結(jié)果
  console.log(allResults)
})

start 回調(diào)有什么作用呢?

方便使用者拿當(dāng)前并發(fā)請求的結(jié)果,方便計算完成進(jìn)度。

把上述功能封裝成 p-control npm 包發(fā)布

npm: p-control

可通過 npm i p-control 下載使用。

小結(jié)

  • .then 和遞歸結(jié)合,實現(xiàn)異步任務(wù)之間等待;
  • forwhile等循環(huán)和async + await結(jié)合使用,實現(xiàn)異步任務(wù)之間等待;
  • 使用Promise.all實現(xiàn)多個異步任務(wù)并發(fā)執(zhí)行。

到此這篇關(guān)于前端如何控制并發(fā)請求的文章就介紹到這了,更多相關(guān)前端控制并發(fā)請求內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論