Ajax异步请求中实现长进程状态轮询与进度条更新
Hey there! Your core idea of using client-side polling to track a long-running server process is solid, but there are a few critical tweaks needed to make this work reliably. Let's walk through the complete, working implementation:
1. Updated Controller Code
First, the status field needs to be static (since each HTTP request creates a new instance of the controller) and we should add thread safety to avoid race conditions between the long process and polling requests.
using System.Threading; using System.Web.Mvc; public class HomeController : Controller { // Static field to hold process status (shared across all requests) private static int _status; // Lock object for thread-safe access to the status value private static readonly object _statusLock = new object(); // Get current status (thread-safe) public JsonResult GetStatus() { lock (_statusLock) { return Json(_status, JsonRequestBehavior.AllowGet); } } // Set status (thread-safe helper method) private void SetStatus(int value) { lock (_statusLock) { _status = value; } } // Simulated long-running process (20 seconds total) public JsonResult LongProcess() { // Reset status at the start of the process SetStatus(0); // Loop from 1 to 10 to reach 100% progress for (int i = 1; i <= 10; i++) { Thread.Sleep(2000); // Simulate work with 2-second delays SetStatus(i); } return Json("Done", JsonRequestBehavior.AllowGet); } }
2. Updated View Code
We'll add better user feedback, error handling, and ensure the progress bar behaves as expected when the process finishes:
<button class="btn btn-primary" id="progressBtn">Start Long Process</button> <div class="progress mt-3" style="width: 500px;"> <div class="progress-bar progress-bar-striped progress-bar-animated" id="probar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"> 0% </div> </div> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $('#progressBtn').on('click', function () { const $btn = $(this); // Disable button to prevent duplicate clicks $btn.prop('disabled', true).text('Processing...'); // Start polling for status updates every 250ms const intervalID = setInterval(updateStatus, 250); // Trigger the long-running server process $.ajax({ type: "POST", url: '/Home/LongProcess', contentType: "application/json", dataType: "json", data: "{}", success: function () { clearInterval(intervalID); // Force progress to 100% when process completes updateProgress(100); $btn.prop('disabled', false).text('Process Completed'); }, error: function () { clearInterval(intervalID); $btn.prop('disabled', false).text('Process Failed'); alert('An error occurred during the long process.'); } }); }); function updateStatus() { $.ajax({ type: "GET", url: '/Home/GetStatus', contentType: "application/json", dataType: "json", success: function(data) { // Convert 0-10 status value to 0-100% progress const percent = data * 10; updateProgress(percent); }, error: function () { console.error('Failed to fetch process status'); } }); } // Helper to update progress bar UI function updateProgress(percent) { const $bar = $('#probar'); $bar.css('width', percent + '%') .attr('aria-valuenow', percent) .text(percent + '%'); } </script>
3. Key Improvements & Notes
- Thread Safety: The
lockstatement ensures that reading/writing the status doesn't cause race conditions when multiple requests (polling + long process) access the static field. - Static Status: Without making
_statusstatic, each controller instance would have its own status value, so polling requests would never see updates from the long process. - User Experience: Added button state changes, animated progress bar styling, and percentage text to keep users informed.
- Error Handling: Properly cleans up the polling interval if the process fails, and gives clear feedback to the user.
- Status Reset: The long process resets the status to 0 at startup, so repeated button clicks work correctly.
内容的提问来源于stack exchange,提问作者Murfcoder
相关产品推荐
相关产品推荐

