2011-11-16 56 views
4

當我在我的viewModel中有一個大的數據集,並且我使用foreach來遍歷一個對象數組來將每個對象呈現爲一個表內的一行時,KnockoutJS會阻塞主線程直到它可以呈現,有時需要幾分鐘(!)。KnockoutJS foreach塊主線程

以下是使用包含2000對象的數據集的jsFiddle示例,其中包含urlcode。實際數據在某些情況下會有更長的URL,而在另外4列(本例中只有2列)中,我也添加了一些簡單的樣式,因爲添加樣式似乎也會在這個過程中減慢速度。

警告:您的瀏覽器威力休息

http://jsfiddle.net/DESC3/7/

+0

這將說明這個問題:http://jsfiddle.net/DESC3/10/它已經減少了數據量,因爲它不需要表達點。 – Esailija

+1

下面是如何使用不同的方法http://jsfiddle.net/DESC3/11/立即呈現相同的html(2000行)。我不是說要這樣做,但它只是表明淘汰賽不是非常優化... – Esailija

+0

@Esailija - 你的第一個例子其實很快。對於大於1000行的我們來說,這只是一個問題。同樣,我們也有一些理由將所有數據都納入其中。因此,分頁或以塊形式發送數據不是真正的選擇。 – RyanScottLewis

回答

1

我建議,如果你有這樣大的數據集,你嘗試另一種解決方案。例如,slickGrid通過僅爲實際可見的數據生成HTML元素,以更有效的方式呈現大型數據集。我們已經將它用於大型數據集,並且性能良好。

1

這樣的事情呢?說,你有viewModel.items = ko.observableArray(),你想呈現。

  1. 有一個單獨的不可觀察數組的所有數據:var itemsToRender = functionThatReturnsLargeArray()
  2. itemsToRender中的部分數據放入可觀察數組中。說只有50個元素。
  3. 保持將元素添加到setTimeout回調中的可觀察數組中。

注1:你可以添加一些時間跟蹤到setTimeout回調和增加/減少您添加在每次迭代的項目數。您的目標是將每個回調時間保持在50-100毫秒以下,以便您的應用程序仍能感覺到響應。

var batchSize = 50; // default number of items rendered per iteration 
var batchOffset = 0; 
function render(items, itemsToRender, done) { 
    setTimeout(function() { 
     var startTime = new Date().getTime(); 
     items.pushAll(itemsToRender.slice(batchOffset, batchSize)); 
     batchOffset += batchSize; 
     // at this point Knockout rendered next batchSize items from itemsToRender 
     var endTime = new Date().getTime(); 
     // update batchSize for next iteration 
     batchSize = batchSize * 50/(endTime - startTime); // 50 milliseconds 
     batchSize = Math.min(itemsToRender.length, batchOffset + batchSize); 
     if (batchSize > 0) render() else done(); // callback if you need one 
    }, 0); 
} 
/* I haven't actually tested the code */ 

另一批量更新策略可以基於目標FPS。假設您希望獲得60 fps的更新速率,因此每1000毫秒需要60個電話給setTimeout。處理整個收藏需要更長的時間。您也可以使用​​而不是setTimeout並查看如何解決問題。

編輯Build-in throttling加入到Knockout JS 1.3(目前它在測試階段,但似乎相當穩定)。


注2:如果認爲其他一些數據取決於viewModel.items你仍然可以映射下來到原數組itemsToRender。比如說,你想顯示收藏中的物品數量。如果您使用viewModel.items().length,則最終會在UI中更改大小值,同時會渲染更多項目。爲了避免這種情況,您可以首先根據itemsToRender定義您的尺寸綁定爲dependentObservable,而不是viewModel.items。完成渲染所有項目後,如果您覺得合適,可將其重新映射到viewModel.items