如何基于JS實現Ajax并發請求的控制詳解
最近看到一個面試題,當然了,就是這篇文章的標題,Ajax的并發請求的控制,感覺挺有意思的,在社區看了下,應該是字節的面試題,也挺多大佬對這個進行了總結,都看了下,于是自己也想試著總結下,代碼文末會全部貼出,如有不足,請指出!
Ajax的串行與并行 串行:一般業務需求是下個接口需要用到上個接口的返回的數據,前端常用的請求庫是Axios,本身就是基于Promise的HTTP庫,我們直接采用鏈式調用,或者采用Async Await 的方式就可以實現,就不做演示了 并行:就是多個請求同時發生,一般情況會用于當所有數據都拿到后進行渲染頁面,或者其他的操作,主要還是基于Promise.all實現方式如下上面模擬實現了基于Promise.all的并行操作,打印結果入下
是不是覺得的這就結束了,不存在的?接下來才是正菜,我們試想有種情況,一個頁面中需要同時發送上萬個請求,全部成功后再去做一些操作,這樣會導致什么后果呢?代碼無法執行,內存溢出,哎~這個時候就回到了我們文章的主題上了,如何對Ajax并發請求的控制呢?我讓他一次性只能輸出一定數量的請求,直到所有的都成功為止,接下來我將用兩種方法實現這個操作,望讀者朋友們不吝賜教
Ajax的并發請求控制的兩大解決方案基于Promise遞歸實現以下的兩種方法都是需要用到上圖中的那個Tasks數組的,請大家記住它,第一中基于Promise的方法,大致思路是:當你傳入一個并發量pool時,會創建pool個工作區,每一個工作區回去拿對應的任務(請求)去執行,成功后保存,然后繼續去拿任務(請求),直到工作區沒有任務了,當然了,失敗直接終止, 大致思路就是這樣,下面我對每一行代碼進行了注釋,請笑納
第二種方法是基于Class來實現的,和上面的區別在于這個只創造一個工作區,大致思路:創建一個工作區用于執行任務(請求),然后將所有任務都推入,但是沒次只能執行對應的并發數,當小于并發數市,繼續去拿任務執行它,直到沒有任務(請求)為止, 就是這樣,下面是具體實現
這里把這兩種方法的實現代碼貼出
const delay = function delay(interval) { return new Promise((res,rej) => {setTimeout(() => { res(interval)}, interval); }) } let tasks = [() => { return delay(1000) },() => { return delay(1003) },() => { return delay(1005) },() => { return delay(1002) },() => { return delay(1004) },() => { return delay(1006) }] // 通過Promise.all實現并行 Promise.all(tasks.map(task => task())).then(res => { console.log(res); }) // 基于Promise實現 function creatRequest(tasks,pool) { // 每次控制的發送請求的數量pool pool = pool || 5 // 用于存儲每一次請求的結果(按順序進行存貯) let results = [], // together 用于創建工作區,當pool傳入的是幾,我們就對應的創建幾個工作區 // 也就是創建一個長度為pool且值為null的一個數組 together = new Array(pool).fill(null), // index為每次獲取的任務值 index = 0; together = together.map(() => {// 基于Promise進行管理return new Promise((resolve,reject) => { // 創建一個函數,進來立刻執行 const run = function run() { // 如果任務池已經空了,說明請求發送完成了,直接成功 if(index >= tasks.length) { resolve() return } // 先將index保存一下用于存儲當前成功請求的結果 let old_index = index, // 獲取當前發送的請求,然后把index進行累加,所以上面會把index保存起來 // 這里index++ 是先運算后累加的,而++index則相反,先累加后運算task = tasks[index++]; // 執行請求 task().then(result => { // 將成功結果保存 results[old_index] = result // 遞歸繼續執行,也就是繼續拿到任務到工作區執行 run(); }).catch(reason => { reject(reason) }) } // 立即執行 run()}) }) // 用Promise.all管控工作區,也就是每次并發兩個請求 return Promise.all(together).then(() => results) } creatRequest(tasks,2).then(results => { // 都成功,整體才成功,按順序存儲結果 console.log(’成功’,results); }).catch(resolve => { // 只要有一個失敗,整體失敗 console.log(’失敗’); }) // 基于Class實現 function creatRequest(tasks,pool,callback) { // 參數的限制與驗證 if(typeof pool === ’function’) {callback = pool;pool = 5 } if(typeof pool !== ’number’) pool = 5 if(typeof callback !== ’function’) callback = function () {} // ------- class TaskQueue {// 正在運行的個數runing = 0;// 將所有任務所存在的隊列queue = [];// 存儲執行任務(請求)的結果results = [];pushTask(task) { let self = this // 將任務推入工作區 self.queue.push(task) // 執行發送請求的邏輯 self.next()}next() { let self = this // 當正在執行的任務數小于并發量的時候繼續去拿任務執行 while(self.runing < pool && self.queue.length) { self.runing++; // 相當于拿一個任務刪除一個任務 let task = self.queue.shift(); // 執行請求 task().then(result => { // 將執行結果保存 self.results.push(result) }).finally(() => { // 將正在運行的個數清除 self.runing-- // 繼續執行請求 self.next() }) } // 當沒有任務了循環結束 if(self.runing === 0) callback(self.results)} } // 實例化 let TQ = new TaskQueue() tasks.forEach(task => TQ.pushTask(task)) } creatRequest(tasks,2,results=> { console.log(results); })總結
以上就是對這套面試題的總結了,也是自己做下記錄,后續會不斷的更新前端方面的文章,最后還是希望各位前端的小伙伴們都能堅持學習,技術不斷提升,加油吧,騷年!!!
到此這篇關于如何基于JS實現Ajax并發請求控制的文章就介紹到這了,更多相關JS實現Ajax并發請求控制內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!
相關文章: