使用處理大型資料集的 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中文網其他相關文章!

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

Node.js擅長於高效I/O,這在很大程度上要歸功於流。 流媒體匯總處理數據,避免內存過載 - 大型文件,網絡任務和實時應用程序的理想。將流與打字稿的類型安全結合起來創建POWE


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Dreamweaver CS6
視覺化網頁開發工具

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

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

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

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。