2011-08-09 47 views
11

因此,我從服務器返回一個大的JSON對象,然後從它構建一個數據表並將它顯示在窗體上。這通常需要幾秒鐘..所以我想到了一個加載欄。 我有加載欄背後的邏輯,但是構建hmtl數據的循環鎖定了瀏覽器,我無法調用我需要更新的元素。如何在Javascript中執行線程操作

這裏是我的功能來做到這一點:

function buildDataTable(db_table, container_id) { 
    var $pb = $("<div id=\"progress-bar\"></div>"); 
    $(container_id).html($pb); 
    $pb.progressbar({ 
     value: 0 
    }); 
    $.post("post location", { 
     view: "all" 
    }, function (data) { 
     var headers = ""; 
     var contents = ""; 
     var jsonObject = $.parseJSON(data); 
     var tik = Math.round(jsonObject.length/100); 
    for (key in jsonObject[0]) { 
      headers += "<th>" + key.replace(" ", "&nbsp;") + "</th>"; 
     } 
     for (i in jsonObject) { 
      contents += "<tr>"; 
      for (j in jsonObject[i]) { 
       contents += "<td class=\"border-right\">" + jsonObject[i][j] + "</td>"; 
      } 
      contents += "</tr>"; 
      if(Math.round(i/tik) == i/tik) { 
/* if I run the alert (between popups) i can see the progressbar update, otherwise I see no update, the progressbar appears empty then the $(container_id) element is updated with the table i've generated */ 
       alert(''); 
       $pb.progressbar("value",i/tik); 
      } 
     } 
     var html = "<table cellpadding=\"5\" cellspacing=\"0\"><thead><tr>" + headers + "</tr></thead><tbody>" + contents + "</tbody></table>"; 

     $(container_id).html(html); 
     $(container_id).children("table:first").dataTable({ 
      "bJQueryUI": true, 
      "sScrollX": "100%" 
     }); 
    }); 
} 
+1

JavaScript是單線程的。您必須將工作分解成幾部分,並使用「setTimeout」按順序調用它們,以便在處理過程中更新GUI,但即使如此,瀏覽器仍然顯得有些反應遲鈍。 – maerics

+0

那麼我最好只使用一個動畫gif而不顯示真正的進展? – rlemon

+0

@maerics:我認爲異步請求打開了一個新的線程? – Anthony

回答

19

[增加了一個答案我的評論]

JavaScript是單線程的。你必須將你的工作分解成幾部分,然後使用「setTimeout」按順序調用它們,以便在處理過程中(在你的調用之間)更新GUI,但即使如此,瀏覽器仍然看起來有些反應遲鈍。

+2

實際上[web workers](http://www.whatwg.org/specs/web-apps/current-work/complete/workers.html)爲'setTimeout'解決方案提供了一個很好的選擇... – revers

+0

@revers:是的,WebWorkers似乎是專門爲這類問題而設計的;然而,這是一個HTML5草案(上次我檢查),所以新的瀏覽器會有一些支持,但行爲會有所不同。老的瀏覽器將不得不像我建議的那樣做一些奇怪的事情。 – maerics

+0

是的,你是對的。看起來IE在第10版之前不會支持它...... – revers

3

您可以嘗試使用WebWorker:https://developer.mozilla.org/en/DOM/Worker
因此工人都在主線程的並行執行,你可以不使用工人正是實現多線程:你不能從一個工人修改UI。
您可以在工作人員中創建網格作爲字符串,當工作人員完成後,將其追加到您想要的位置。

+0

似乎他們的HTTP Secure存在問題....無法加載https下的任何頁面 – rlemon

+0

您也可以查看[本頁](http://www.html5rocks.com/en/tutorials/workers/基礎知識/#toc-envi n n n nv-subworkers)。但是,maerics提到Web工作人員非常新,只有新瀏覽器支持。 – revers

2

如果您在setTimeout中完成數據庫的所有構建,則頁面的其餘部分應該是響應式的。

您可以在該函數中構造html元素,並在準備好時將其附加到DOM。您還必須調用函數或發送事件來更新進度條的顯示。評論後

編輯:

這將在後臺運行,不會影響網頁的響應:

window.setTimeout(function() {buildDataTable(db_table, container_id)}, 0);

你已經從你的函數更新進度,所以這應該做到這一點。

但是,您可能想要將生成數據表的代碼與代碼更新進度條分離。

+0

你能澄清這一點嗎?將函數調用包裝在setTimeout(function(){** Function Call **},0)中; – rlemon

+0

如果buildDataTable是一個長時間運行的任務(並且OP表示它是這樣的),那麼這種方法不會解決無響應的UI問題,因爲它會在運行時阻塞(它可能會在開始運行之前允許其他事情)。您需要將任務分解爲更小的塊,併爲每個塊調用setTimeout以獲得某種分時。 – UpTheCreek

0

所以它似乎在我的應用程序中這樣做的唯一干淨方式是處理服務器上的json並在那裏構建html。 然後通過$.post()返回html到瀏覽器

進度條會丟失。但我可以使用無限的加載gif ...