Swift中使用PromiseKit实现分页的技术问询
Hey there! I’ve worked with PromiseKit extensively for chained API workflows, so let’s walk through how to build clean, reliable pagination using its chaining capabilities. The core idea is to recursively fetch pages until we hit the end of the dataset, leveraging PromiseKit’s ability to chain asynchronous operations seamlessly.
Step 1: Define a Reusable Page-Fetching Promise
First, create a function that fetches a single page of data and returns a Promise. This function should handle the API call, parse the response, and return both the page data and a flag indicating if there’s a next page to fetch.
func fetchPage(pageNumber: Int) -> Promise<(data: [YourDataModel], hasNextPage: Bool)> { return Promise { seal in // Set up your API request (adjust URL and parameters to match your API) guard let url = URL(string: "https://yourapi.com/items?page=\(pageNumber)") else { seal.reject(NSError(domain: "APIError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])) return } URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { seal.reject(error) return } guard let data = data else { seal.reject(NSError(domain: "APIError", code: -2, userInfo: [NSLocalizedDescriptionKey: "No data returned"])) return } // Parse the API response (adjust decoding to match your response structure) do { let pageResponse = try JSONDecoder().decode(PageResponse.self, from: data) let hasNextPage = pageResponse.nextPage != nil // Use your API's pagination indicator (e.g., has_more, next_cursor) seal.fulfill((pageResponse.items, hasNextPage)) } catch { seal.reject(error) } }.resume() } } // Example response model (match your API's structure) struct PageResponse: Codable { let items: [YourDataModel] let nextPage: Int? // Or a boolean like `hasMore` }
Step 2: Build a Recursive Pagination Chain
Next, create a recursive function that starts with the first page, accumulates data as it fetches each page, and stops when there are no more pages left. This is where PromiseKit’s chaining shines—each page fetch waits for the previous one to complete before proceeding.
func fetchAllPages(startingAt page: Int = 1, accumulatedData: [YourDataModel] = []) -> Promise<[YourDataModel]> { return fetchPage(pageNumber: page).then { pageData, hasNextPage in let combinedData = accumulatedData + pageData guard hasNextPage else { // No more pages to fetch—return all accumulated data return Promise.value(combinedData) } // Recursively fetch the next page, passing along the accumulated data return fetchAllPages(startingAt: page + 1, accumulatedData: combinedData) } }
Step 3: Use the Pagination Function
Now you can call the pagination function and handle the final result (or errors) using PromiseKit’s standard done/catch handlers:
fetchAllPages() .done { allFetchedData in // Do something with all your paginated data! print("Successfully fetched \(allFetchedData.count) items total") } .catch { error in // Handle any errors that occurred during pagination print("Pagination failed: \(error.localizedDescription)") }
Pro Tips for Robustness
- Error Resilience: If you want to skip failed pages instead of aborting the entire chain, add a
recoverhandler insidefetchPageto return an empty page and continue. - Rate Limiting: If your API has rate limits, add a small delay between requests using
after(seconds:)before recursively callingfetchAllPages. - Cancellation: To support canceling the pagination flow (e.g., if the user navigates away), wrap the chain in a
CancellablePromiseand use PromiseKit’s cancellation tokens.
内容的提问来源于stack exchange,提问作者darshan

