搜索场景下setTimeout相关问询:StatusChecker类服务器请求实现
Hey there! Looking at your StatusChecker class, it seems you're trying to poll a server for search completion status—perfect use case for timed requests. Let's walk through practical setTimeout (and related) implementations tailored to your code.
First, Let's Recap Your Current Flow
Your class either loads results immediately if the search is already done, or fires an initial AJAX request to check status. To add polling, we'll extend this to re-check status at intervals until the search completes or hits an error.
1. Recursive setTimeout Polling (Recommended)
Instead of setInterval (which can pile up requests if the server is slow), use recursive setTimeout—it waits for the previous request to finish before scheduling the next one. This prevents overlapping requests.
Here's how to update your class:
export default class StatusChecker { // Track timeout ID for cleanup private pollTimeoutId?: number; // Define poll interval (adjust based on your needs, e.g., 2000ms = 2s) private readonly POLL_INTERVAL = 2000; constructor() { if (gon.search && gon.search.searched) { this.final_load(); } else { this.make_request(); } } private make_request() { $.ajax({ url: "/search/status", type: "GET", context: this, // Keep class instance as context data: { search_id: gon.search["id"] }, success: this.handle_response, error: this.handle_response_error }); } private handle_response(response: any) { if (response.searched) { // Search complete: clean up timeout and load results this.clearPollTimeout(); this.final_load(); } else { // Search still running: schedule next check this.pollTimeoutId = window.setTimeout(() => { this.make_request(); }, this.POLL_INTERVAL); } } private handle_response_error() { console.error("Failed to check search status"); this.clearPollTimeout(); // Optional: Retry a few times before giving up // this.pollTimeoutId = window.setTimeout(() => this.make_request(), this.POLL_INTERVAL); } // Helper to clean up timeout (prevents memory leaks) private clearPollTimeout() { if (this.pollTimeoutId) { window.clearTimeout(this.pollTimeoutId); this.pollTimeoutId = undefined; } } // Optional: Public method to stop polling (e.g., user navigates away) public stopPolling() { this.clearPollTimeout(); } private final_load() { // Your existing logic to load completed results console.log("Loading finished search results"); } }
Key Notes:
- Recursive Timing: We only schedule the next request after the current one resolves, avoiding request overlap.
- Cleanup: Added
clearPollTimeoutto prevent memory leaks (critical for single-page apps where components unmount). - Context Binding: Used
context: thisin the AJAX call and arrow functions insetTimeoutto keepthispointing to the class instance.
2. Polling with Retry Limits & Total Timeout
To avoid infinite polling (e.g., if the server hangs), add a maximum number of retries or total timeout:
export default class StatusChecker { private pollTimeoutId?: number; private readonly POLL_INTERVAL = 2000; private retryCount = 0; private readonly MAX_RETRIES = 10; // Stop after 10 attempts (20s total) constructor() { // ... existing constructor code } private handle_response(response: any) { if (response.searched) { this.clearPollTimeout(); this.final_load(); } else if (this.retryCount < this.MAX_RETRIES) { this.retryCount++; this.pollTimeoutId = window.setTimeout(() => { this.make_request(); }, this.POLL_INTERVAL); } else { this.clearPollTimeout(); console.error("Max retries reached—stopping poll"); // Notify user of timeout here } } // ... rest of the class code }
3. Modern Alternative: Using AbortController (Cancelable Requests)
If you need to cancel in-flight requests (e.g., when the user navigates away), use AbortController (supported in all modern browsers):
export default class StatusChecker { private pollTimeoutId?: number; private abortController?: AbortController; private readonly POLL_INTERVAL = 2000; private make_request() { // Create new controller for each request this.abortController = new AbortController(); $.ajax({ url: "/search/status", type: "GET", context: this, data: { search_id: gon.search["id"] }, success: this.handle_response, error: this.handle_response_error, // Pass abort signal to cancel request if needed xhrFields: { signal: this.abortController.signal } }); } private clearPollTimeout() { if (this.pollTimeoutId) { window.clearTimeout(this.pollTimeoutId); this.pollTimeoutId = undefined; } // Cancel any in-flight request if (this.abortController) { this.abortController.abort(); this.abortController = undefined; } } // ... rest of the class code }
Pro Tips for Your Search Scenario
- Adjust Poll Interval: Don't poll too frequently (e.g., <1s) — it strains the server. 2-5 seconds is usually reasonable for search status checks.
- Server-Side Feedback: Make sure your
/search/statusendpoint returns clear statuses (e.g.,searched: boolean,progress: numberif you want to show a loading bar). - User Feedback: Show a loading indicator while polling, and update it if the poll takes longer than expected.
内容的提问来源于stack exchange,提问作者Silco

