位元組跳動面試之如何用JS實現Ajax併發請求控制
前言
講真的,最近也很迷茫。關於技術、關於生活吧。也找了很多在大廠的朋友去聊,想需求一些後期發展的思路。這其中也聊到了面試,聊到了招聘中會給面試者出的一些題目。我正好也好久沒面試了,就從中選了幾道。最近也會陸續出一系列關於一些面試問題的解析。
今天這道是位元組跳動的:
實現一個批量請求函式 multiRequest(urls,maxNum),要求如下:
• 要求最大併發數 maxNum
• 每當有一個請求返回,就留下一個空位,可以增加新的請求
• 所有請求完成後,結果按照 urls 裡面的順序依次打出
這道題目我想很多同學應該都或多或少的見過,下面我會依次從出現的場景、問題的分析到最終的實現,一步步力求深入淺出的給出這道題目的完整解析。
場景
假設現在有這麼一種場景:現有 30 個非同步請求需要傳送,但由於某些原因,我們必須將同一時刻併發請求數量控制在 5 個以內,同時還要儘可能快速的拿到響應結果。
應該怎麼做?
首先我們來了解一下 Ajax的序列和並行。
基於 Promise.all 實現 Ajax 的序列和並行
程式設計客棧我們平時都是基於promise來封裝非同步請求的,這裡也主要是針對非同步請求來展開。
- 序列:一個非同步請求完了之後在進行下一個請求
- 並行:多個非同步請求同時進行
通過定義一些promise例項來具體演示序列/並行。
序列
var p = function () { return new Promise(function (resolve,reject) { setTimeout(() => { console.log("1000"); resolve(); },1000); }); }; var p1 = function () { return new Promise(function (resolve,reject) { setTimeout(() => { console.log("2000"); resolve(); },2000); }); }; var p2 = function () { return new Promise(function (resolve,reject) { setTimeout(() => { console.log("3000"); resolve(); },3000); }); }; p() .then(() => { return p1(); }) .then(() => { return p2(); }) .then(() => { console.log("end"); });
如示例,EJHeYEXFc序列會從上到下依次執行對應介面請求。
並行
通常,我們在需要保證程式碼在多個非同步處理之後執行,會用到:
Promise.all((promises: [])).then((fun: function)); Promise.all可以保證,promises陣列中所有promise物件都達到resolve狀態,才執行then回撥。 var promises = function () { return [1000,2000,3000].map((current) => { return new Promise(function (resolve,reject) { setTimeout(() => { console.log(current); },current); }); }); }; Promise.all(promises()).then(() => { cEJHeYEXFconsole.log("end"); });
Promise.all 併發限制
這時候考慮一個場景:如果你的promises陣列中每個物件都是http請求,而這樣的物件有幾十萬個。
那麼會出現的情況是,你在瞬間發出幾十萬個http請求,這樣很有可能導致堆積了無數呼叫棧導致記憶體溢位。
這時候,我們就需要考慮對Promise.all做併發限制。
Promise.all併發限制指的是,每個時刻併發執行的promise數量是固定的,最終的執行結果還是保持與原來的Promise.all一致。
題目實現
思路分析
整體採用遞迴呼叫來實現:最初發送的請求數量上限為允許的最大值,並且這些請求中的每一個都應該在完成時繼續遞迴傳送,通過傳入的索引來確定了urls裡面具體是那個URL,保證最後輸出的順序不會亂,而是依次輸出。
程式碼實現www.cppcns.com
function multiRequest(urls = [],maxNum) {EJHeYEXFc // 請求總數量 const len = urls.length; // 根據請求數量建立一個數組來儲存請求的結果 const result = new Array(len).fill(false); // 當前完成的數量 let count = 0; return new Promise((resolve,reject) => { // 請求maxNum個 while (count < maxNum) { next(); } function next() { let current = count++; // 處理邊界條件 if (current >= len) { // 請求全部完成就將promise置為成功狀態,然後將result作為promise值返回 !result.includes(false) && resolve(result); return; } const url = urls[current]; console.log(`開始 ${current}`,new Date().toLocaleString()); fetch(url) .then((res) => { // 儲存請求結果 result[current] = res; console.log(`完成 ${current}`,new Date().toLocaleString()); // 請求沒有全部完成,就遞迴 if (current < len) { next(); } }) .catch((err) => { console.log(`結束 ${current}`,new Date().toLocaleString()); result[current] = err; // 請求沒有全部完成,就遞迴 if (current < len) { next(); } }); } }); }
總結
到此這篇關於位元組跳動面試之如何用js實現Ajax併發請求控制的文章就介紹到這了,更多相關JS實現Ajax併發請求控制內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!