2013-02-21 59 views
0

所以我試圖添加一個異步進度欄上一個非常緩慢和長的查詢,插入一堆行到數據庫。我的實現是基於關閉這個例子:http://blog.janjonas.net/2012-01-02/asp_net-mvc_3-async-jquery-progress-indicator-long-running-tasks異步jQuery數據庫循環 - 幫助實施進度條

下面是進度條

function updateMonitor(taskId, status) { 
     $("#monitors").html("Task [" + taskId + "]: " + status); 
    } 
//other code 
if (doSend == true) { 
      $.post("/SendBatch/HandleBatchRequest", { 
       //other code 
      }, 
      function (taskId) { 

       // Init monitors 
       //breakpoint here only stops it once the "/SendBatch/HandleBatchRequest" is done. PROBLEM. 
       $("#monitors").append($("<p id='" + taskId + "'/>")); 
       updateMonitor(taskId, "Started"); 

       // Periodically update monitors 
       var intervalId = setInterval(function() { 
        $.post("SendBatch/Progress", { id: taskId }, function (progress) { 
        if (progress >= 100) { 
         updateMonitor(taskId, "Completed"); 
         clearInterval(intervalId); 
        } else { 
         updateMonitor(taskId, progress + "%"); 
        } 
       }); 
      }, 100); 
     }  
     ,"html"); 

的JavaScript代碼然後是網站

<div id="monitors"></div> 

這裏的顯示部分中的DIV控制器外觀如何

public SendBatchController 
    //some code 
private static IDictionary<Guid, int> tasks = new Dictionary<Guid, int>(); 

public ActionResult HandleBatchRequest(
     //some code 
    ) 
    { 
     var taskId = Guid.NewGuid(); 
     tasks.Add(taskId, 0); 



     var batchId = Guid.NewGuid().ToString("N"); 
     var costd = cost.ToDecimal(); 

     IEnumerable<BatchListModel> customers; 

     try 
     { 
      customers = new CustomerService(_customerRepository.Session).GetCustomers(
       //some code 
       ); 
     } 
     catch (Exception err) 
     { 
      return Json(err.Message); 
     } 
     if (doSend) 
     { 
      var sent = 0; 

      foreach (var c in customers) 
      { 
       try 
       { 
        var usr = _customerRepository.LoadByID(c.ID); 

        var message = new ComLog 
             { 
              //insertions to log 
             }; 

        _comLogRepository.Save(message); 
        sent++; 

        //progress bar part inside here that is important comes here: 
        tasks[taskId] = sent; 

       } 
       catch (Exception e) 
       { 
        Log.WriteLine("ERR:" + e); 
       } 

       tasks.Remove(taskId); 

      } 
      return Json(taskId); 

     } 

     return Json(customers.Count() + " customers"); 
    } 

    public ActionResult Progress(Guid id) 
    { 
     return Json(tasks.Keys.Contains(id) ? tasks[id] : 100); 
    } 

這樣做不行。該過程在後臺運行。查詢完成後,DIV會顯示「Complete」消息。它在查詢過程中不顯示。我不確定異步的東西如何工作,所以這裏可能會出現一些邏輯錯誤。例如,它甚至知道總共有多少客戶?代碼的另一個關鍵部分是「任務[taskId] =發送;」至於我不確定是否正確完成。

回答

0

我強烈建議不要在setInterval函數中使用ajax。相反,在$ .post()的success/complete回調函數中使用setTimeout。這將保證請求是按順序生成的。

如果你每隔100ms發送一次ajax請求,它們將很快失去同步並且無疑會導致問題。

1

在javascript方面,開始進度檢查的函數在請求成功完成HandleBatchRequest之後纔會觸發。 $.post()的第三個參數是在成功請求後觸發的。

您將需要讓C#控制器立即返回任務ID,並將數據庫插入到另一個線程/後臺工作器(下面會詳細介紹)。或者讓Javascript隨機生成taskId並傳入C#控制器。

從那裏,正如布拉德提到的,你不想在它內部做一個ajax請求的setInterval。由於AJAX是異步的,您可能會在服務器返回響應之前等待一段時間。爲了防止多個請求的發生立刻和導致撤消在後端服務器上的壓力,你會想要做的事,如:

var taskId = 0; 
$.post('/SendBatch/HandleBatchRequest', {}, function(r) { 
    taskId = r; // set task id from 
    $("#monitors").append($("<p id='" + taskId + "'/>")); 
    CheckProgress(); 
}, 'html'); 

function CheckProgress() { 
    $.post("SendBatch/Progress", { id: taskId }, function (progress) { 
    if (progress >= 100) { 
     updateMonitor(taskId, "Completed"); 
    } else { 
     updateMonitor(taskId, progress + "%"); 
     setTimeout(function() { 
      CheckProgress() 
     }, 1000); 
    } 
} 

對事物的C#方,該控制器被實例化在每個Web請求,所以當你去檢查進度時,tasks將是空的。您需要將實際記錄加載到某種背景工作/線程中,以完成從控制器插入記錄的實際工作。如果您經常這樣做,您可能需要查看服務器上安裝的某種後臺服務,這些後臺服務可持續運行以優化事情併爲您提供最佳的靈活性。

0

爲什麼不只是添加加載GIF到您的網站(你可以從這裏下載 - http://www.ajaxload.info/)然後posistion在一個div這個加載GIF在網頁上 - 徘徊無論你是想它來顯示。

喜歡的東西下面

<div><img class="hidden " id="LoadingGif" src='../Content/Styles/images/loading.gif' height="100" /></div> 

然後在你的js文件的Simplay刪除類隱藏在LoadingGif ID,並可能添加類隱到您的顯示器股利。

隱藏類應該有如下您的site.css

.hidden {visibility:hidden; display:none;}