使用處理大型資料集的 API 時,有效管理資料流並解決分頁、速率限制和記憶體使用等挑戰至關重要。在本文中,我們將介紹如何使用 JavaScript 的本機 fetch 函數來使用 API。我們將看到重要的主題,例如:
- 處理大量資料:增量檢索大型資料集以避免系統不堪負荷。
- 分頁:大多數 API(包括 Storyblok Content Delivery API)以頁面形式傳回資料。我們將探索如何管理分頁以實現高效的資料檢索。
- 速率限制:API 通常會施加速率限制以防止濫用。我們將了解如何檢測和處理這些限制。
- Retry-After機制:如果API回應429狀態碼(請求過多),我們將實作「Retry-After」機制,指示重試之前需要等待多長時間,以確保資料流暢正在取得。
- 並發請求:並行取得多個頁面可以加快進程。我們將使用 JavaScript 的 Promise.all() 發送並發請求並提高效能。
- 避免記憶體洩漏:處理大型資料集需要仔細的記憶體管理。借助生成器。 ,我們將分塊處理資料並確保記憶體高效操作
我們將使用 Storyblok Content Delivery API 來探索這些技術,並解釋如何使用 fetch 在 JavaScript 中處理所有這些因素。讓我們深入研究程式碼。
使用 Storyblok Content Delivery API 時要記住的事項
在深入研究程式碼之前,請先考慮以下 Storyblok API 的一些關鍵功能:
- CV 參數:cv(內容版本)參數檢索快取的內容。 cv 值在第一個請求中返回,並應在後續請求中傳遞,以確保獲取內容的相同快取版本。
- 分頁和每頁分頁:使用 page 和 per_page 參數來控制每個請求中傳回的項目數並迭代結果頁面。
- 總標題:第一個回應的總標題指示可用項目的總數。這對於計算需要獲取多少數據頁至關重要。
- 處理 429(速率限制):Storyblok 強制執行速率限制;當您點擊它們時,API 會傳回 429 狀態。使用 Retry-After 標頭(或預設值)了解重試請求之前需要等待多久。
使用 fetch() 處理大型資料集的 JavaScript 範例程式碼
以下是我如何使用 JavaScript 中的本機 fetch 函數來實現這些概念。
考慮一下:
- 此程式碼片段建立一個名為 Stories.json 的新檔案作為範例。如果該檔案已經存在,它將被覆蓋。因此,如果工作目錄中已有具有該名稱的文件,請更改程式碼片段中的名稱。
- 由於請求是並行執行的,因此無法保證故事的順序。例如,如果第三頁的回應比第二個請求的回應快,則生成器將在第二頁的故事之前傳送第三頁的故事。
- 我用 Bun 測試了該片段:)
import { writeFile, appendFile } from "fs/promises"; // Read access token from Environment const STORYBLOK_ACCESS_TOKEN = process.env.STORYBLOK_ACCESS_TOKEN; // Read access token from Environment const STORYBLOK_VERSION = process.env.STORYBLOK_VERSION; /** * Fetch a single page of data from the API, * with retry logic for rate limits (HTTP 429). */ async function fetchPage(url, page, perPage, cv) { let retryCount = 0; // Max retry attempts const maxRetries = 5; while (retryCount setTimeout(resolve, retryAfter * 1000 * retryCount)); continue; } if (!response.ok) { throw new Error( `Failed to fetch page ${page}: HTTP ${response.status}`, ); } const data = await response.json(); // Return the stories data of the current page return data.stories || []; } catch (error) { console.error(`Error fetching page ${page}: ${error.message}`); return []; // Return an empty array if the request fails to not break the flow } } console.error(`Failed to fetch page ${page} after ${maxRetries} attempts`); return []; // If we hit the max retry limit, return an empty array } /** * Fetch all data in parallel, processing pages in batches * as a generators (the reason why we use the `*`) */ async function* fetchAllDataInParallel( url, perPage = 25, numOfParallelRequests = 5, ) { let currentPage = 1; let totalPages = null; // Fetch the first page to get: // - the total entries (the `total` HTTP header) // - the CV for caching (the `cv` atribute in the JSON response payload) const firstResponse = await fetch( `${url}&page=${currentPage}&per_page=${perPage}`, ); if (!firstResponse.ok) { console.log(`${url}&page=${currentPage}&per_page=${perPage}`); console.log(firstResponse); throw new Error(`Failed to fetch data: HTTP ${firstResponse.status}`); } console.timeLog("API", "After first response"); const firstData = await firstResponse.json(); const total = parseInt(firstResponse.headers.get("total"), 10) || 0; totalPages = Math.ceil(total / perPage); // Yield the stories from the first page for (const story of firstData.stories) { yield story; } const cv = firstData.cv; console.log(`Total pages: ${totalPages}`); console.log(`CV parameter for caching: ${cv}`); currentPage++; // Start from the second page now while (currentPage fetchPage(url, page, perPage, firstData, cv), ); // Wait for all requests in the batch to complete const batchResults = await Promise.all(batchRequests); console.timeLog("API", `Got ${batchResults.length} response`); // Yield the stories from each batch of requests for (let result of batchResults) { for (const story of result) { yield story; } } console.log(`Fetched pages: ${pagesToFetch.join(", ")}`); } } console.time("API"); const apiUrl = `https://api.storyblok.com/v2/cdn/stories?token=${STORYBLOK_ACCESS_TOKEN}&version=${STORYBLOK_VERSION}`; //const apiUrl = `http://localhost:3000?token=${STORYBLOK_ACCESS_TOKEN}&version=${STORYBLOK_VERSION}`; const stories = fetchAllDataInParallel(apiUrl, 25,7); // Create an empty file (or overwrite if it exists) before appending await writeFile('stories.json', '[', 'utf8'); // Start the JSON array let i = 0; for await (const story of stories) { i++; console.log(story.name); // If it's not the first story, add a comma to separate JSON objects if (i > 1) { await appendFile('stories.json', ',', 'utf8'); } // Append the current story to the file await appendFile('stories.json', JSON.stringify(story, null, 2), 'utf8'); } // Close the JSON array in the file await appendFile('stories.json', ']', 'utf8'); // End the JSON array console.log(`Total Stories: ${i}`);
關鍵步驟說明
以下是程式碼中關鍵步驟的細分,可確保使用 Storyblok Content Delivery API 實現高效且可靠的 API 使用:
1) 使用重試機制取得頁面(fetchPage)
此函數處理從 API 取得單頁資料。它包括當 API 回應 429(請求過多)狀態時重試的邏輯,這表示已超出速率限制。
retryAfter 值指定在重試之前等待的時間。我在發出後續請求之前使用 setTimeout 暫停,並且重試次數最多限制為 5 次。
2) 初始頁請求與 CV 參數
第一個 API 請求至關重要,因為它會檢索總標頭(指示故事總數)和 cv 參數(用於快取)。
您可以使用total header來計算所需的總頁數,cv參數確保使用快取的內容。
3) 處理分頁
分頁是使用 page 和 per_page 查詢字串參數來管理的。程式碼請求每頁 25 個故事(您可以調整此值),總標題有助於計算需要取得的頁面數。
該程式碼一次最多可批量獲取 7 個(您可以調整此)並行請求的故事,以提高效能,而不會壓垮 API。
4) 使用 Promise.all() 的並發請求:
為了加快流程,使用 JavaScript 的 Promise.all() 並行取得多個頁面。此方法同時發送多個請求並等待所有請求完成。
每批並行請求完成後,將處理結果以產生故事。這樣可以避免一次將所有資料載入到記憶體中,從而減少記憶體消耗。
5) 非同步迭代的記憶體管理(用於await...of):
我們沒有將所有資料收集到數組中,而是使用 JavaScript 生成器(function* 和 wait...of)來處理獲取的每個故事。這可以防止處理大型資料集時出現記憶體過載。
透過一一產生故事,程式碼保持高效並避免記憶體洩漏。
6) 速率限制處理:
如果 API 以 429 狀態代碼(速率受限)回應,則腳本使用 retryAfter 值。然後,它會暫停指定的時間,然後重試請求。這可確保符合 API 速率限制並避免過快發送過多請求。
結論
在本文中,我們介紹了使用本機 fetch 函數在 JavaScript 中使用 API 時的關鍵注意事項。我嘗試處理:
- 大型資料集:使用分頁取得大型資料集。
- 分頁:使用 page 和 per_page 參數管理分頁。
- 速率限制和重試機制:處理速率限制並在適當的延遲後重試請求。
- 並發請求:使用 JavaScript 的 Promise.all() 並行取得頁面,以加快資料擷取速度。
- 記憶體管理:使用JavaScript產生器(function*和await...of)來處理資料而不消耗過多的記憶體。
透過應用這些技術,您可以以可擴展、高效且記憶體安全的方式處理 API 消耗。
請隨時發表您的評論/回饋。
參考
- JavaScript 生成器
- 建置 JavaScript 執行時期
- Storyblok 內容傳遞 API
以上是JavaScript 中海量資料的高效能 API 消耗的詳細內容。更多資訊請關注PHP中文網其他相關文章!

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境