2012-11-09 61 views
3

我有多個需要在系列中調用的進程(我正在使用同步AJAX調用)。我想在完成後顯示長時間運行的進程的狀態,然後進入下一個進程。這是我寫的一個示例代碼。如何在AJAX/Javascript中調用長時間運行的過程時更新UI?

var counter = 0; 
function runProcess(input, output) { 
    doWork(); 
    doWork(); 
    doWork(); 
}; 
function doWork() { 
    counter++; 
    document.getElementById('<%=this.progressMonitor.ClientID%>').innerHTML += "Running " + counter; 

    // some lengthy calculations 
    for (var i = 0; i < 1000000; i++) { 
     var foo = Math.random(); 
    } 
    setTimeout(updateStatus, 1000); 
}; 
function updateStatus() { 
    document.getElementById('<%=this.progressMonitor.ClientID%>').innerHTML += "Done " + counter; 
} 

當我跑,我得到如下回應:

運行1運行2Running 3Done 3Done 3Done 3

我想獲得

運行1Done 1運行2Done 2Running 3Done 3

如果我在updateStatus功能插入一個警報()語句,然後我得到的我想要的響應/執行順序。瀏覽器是否爲3個函數調用創建3個線程並異步執行它們?

我怎樣才能在系列跑的? setTimeout是否正確實施?感謝您的幫助提前。

+0

Ajax調用如何在這裏?他們是否會去你樣本中有數學循環的地方? – slashingweapon

+0

感謝您的幫助。我剛剛注意到你以前的帖子。爲了澄清,這是一個示例代碼。在現實世界中,doWork將被一個CallService函數替代,該函數將同步調用WCF服務。 – akash

回答

1

這聽起來像你要排隊AJAX調用。 jQuery提供了一個好的隊列函數,所以你可以確保一系列函數被一個接一個地調用。 Mootools和其他框架提供了類似的功能。

以下是我的fiddle的代碼,它顯示瞭如何操作。

var queueElement = $("#output"); 
var counter = 0; 

function doWork(next) { 
    queueElement.append("Starting " + counter + "<br/>"); 
    counter++; 
    $.ajax('/echo/json/').always(function() { 
     queueElement.append("Ending " + counter + "<br/>"); 
     next(); 
    }); 
} 

queueElement.queue('workQueue', doWork); 
queueElement.queue('workQueue', doWork); 
queueElement.queue('workQueue', doWork); 
queueElement.dequeue('workQueue'); // start the work queue 
0

一個你必須瞭解有關JavaScript在瀏覽器中的事情是,它是單線程的。當您更改DOM時,屏幕不會更改,直到您的腳本放棄控制。

這裏是事件)的真實順序當你打電話的doWork(兩次:

  1. 呼叫doWork()
  2. doWork()增加了運行的消息
  3. 排隊updateStatus()調用執行後
  4. 通話doWork()再次
  5. doWork()增加了運行的消息
  6. 排隊updateStatus()調用執行後
  7. runProcess()退出,並把控制返回給瀏覽器
  8. 瀏覽器更新屏幕與正在運行的消息
  9. 第一updateStatus()調用。它完成後,屏幕更新
  10. 第二updateStatus()調用。它完成後,屏幕更新

你可以得到你想要通過不與updateStatus()呼叫都搞亂了什麼,只是從內doWork()打印出您已處理完畢的消息。

+0

謝謝。這讓我感覺更好,因爲你的解釋是它仍然是單線程的。我遇到的問題是瀏覽器執行所有事情,然後發送響應(所有內容一起)。我希望在每項服務完成後立即通知用戶。我認爲setTimeout會給瀏覽器足夠的時間來顯示消息,但它似乎不起作用。我已經嘗試了很多代碼示例,但一直未能弄清楚。我在Windows 7上使用IE9。再次感謝。 – akash

+0

有一種方法可以對ajax調用進行排隊,以便它們依次執行。我將處理一個樣本並將其發佈在新的答案中。 – slashingweapon

0

隊列的偉大工程。使用需要在系列中調用的$ .ajax方法上的隊列效果很好。如果我在不使用隊列的情況下使用「async:false」選項,則只有在所有長時間運行的進程完成後纔會刷新UI。

感謝您指點我正確的方向!這裏是我最後的代碼,以防萬一誰在尋找:

function callService(url, workflowid, modelid, next) { 
     var jData = {}; 
     jData.workflowid = workflowid; 
     jData.modelid = modelid; 
     //alert(JSON.stringify(jData)); 
     $.ajax({ 
      url: url, 
      type: "POST", 
      dataType: "json", 
      contentType: "application/json; charset=utf-8;", 
      async: true, 
      cache: false, 
      data: JSON.stringify(jData), 
      success: function (oResult) { 
       $("#Message").append("&nbsp;&nbsp;" + oResult.Message); 
       if (!oResult.Success) { 
        $("#<%:this.FailureText.ClientID %>").append("&nbsp;&nbsp;" + oResult.Error); 
       } else { next(); } 
      }, 
      error: function (exc) { 
       $("#Message").append("&nbsp;&nbsp;" + exc.responseText); 
      } 
     }); 
    } 
    function runServices() { 
     var queueElement = $("#q"); 
     var queueStatus = $("#Message"); 

     queueStatus.append("<br/>Starting workflows at : " + new Date() + "<br/>"); 
     var list = $(":input:checkbox:checked"); // getting all selected checkboxes. 
     $(list.each(function() { 
      var workflowid = $(this).val(); 
      queueElement.queue("WorkflowQ", function (next) { 
       callService("/Services/Workflow.svc/rest/runworkflow", workflowid, document.getElementById('<%=this.MODELID.ClientID%>').value, next); 
      }); 
     }));   
     queueElement.dequeue("WorkflowQ"); 
    }; 

    <input type="button" id="ExecuteButton" value="Execute Workflow" class="button" onclick="runServices();"/> 

<div id="Message"></div> 
<div id="q"></div> 
相關問題