2016-08-12 68 views
0

我遇到了使用KnockoutJS foreach綁定與大型數據集結合的問題。目前,我將我的容器div的「數據」綁定設置爲一個函數,該函數執行ajax調用以獲取數據,在JS對象中解析它,並將每個結果推送到可觀察數組中。KnockoutJS - 在foreach綁定中的異步加載

當我的數據集很小(0-50)時,這種方法效果很好。但是,只要我開始擁有100多條記錄,總時間就會顯着增加。我發現只要數據開始處理,瀏覽器的線程就會「鎖定」,直到所有元素都被解析並添加到數組中。最後,它會將內容加載到dom中,並一次性全部「彈出」。

我想知道是否有一種方法可以通過將元素延遲加載到DOM中進行修改。具體來說,我希望DOM能夠在處理每個元素時處理它,而不是等待所有元素被處理。

感謝

+2

你可以放在一起能重現問題的jsfiddle或片段? – JohnnyHK

+1

使用這裏討論的技術大大提高了我在大數據集下的應用程序性能 - http://www.knockmeout.net/2012/04/knockoutjs-performance-gotcha.html – dmoo

+0

檢出https://github.com/brianmhunt/knockout -fast-的foreach –

回答

0

既然你have've沒有發佈的代碼片段我解釋,你可以做各種可能的方法之一。 您可以更改您的服務器端代碼,以便能夠處理延遲加載的方式返回數據。
然後,你需要有一個間隔函數,它繼續調用一個函數,該函數在你檢查一個標誌,如果你最後的ajax調用返回數據,然後調用下一個ajax。
在您的響應數據中,如果有更多數據,總項目等,那麼可以跟蹤數據。然後在您的Ajax成功回調中更新observables變量,您可以使用它們發送請求數據(如NextPage等),如果沒有更多的數據,你取消了setInterval函數。


下面僅僅是如何實現這種方法(未測試)
JS的例子:

var YourViewModel = function() { 
    var self = this ; 
    var loadMoreTimer; 
    self.IsMoreItems = ko.observable(false); 
    self.LoadingMoreInProcess = ko.observable(false); 
    self.CurrentPage = ko.observable(0); 
    self.Items = ko.observableArray([]); 

    self.AutomaticLoadItem = function() { 
     loadMoreTimer = setInterval(callLoadMore, 500); 
    } 

    function callLoadMore() { 
     if (self.IsMoreItems()) { 
     if (!self.LoadingMoreInProcess()) { 
      self.LoadMore(); 
     } 
     } 
    } 
    self.LoadMore = function() { 
     self.CurrentPage(self.CurrentPage() + 1); 
     self.LoadingMoreInProcess(true); 
     data = {requestPage : self.CurrentPage(), numberOfItem : 20, ...} 
     //your ajax call here 
     $.ajax({ 
      url:..., 
      type: ....,  
      data: data,  
      success: function(response){ 
      // here you check if there is more data left 
       if(response.isMoreData){ 
       // set it to false so the next ajax call can be executed. 
       self.LoadingMoreInProcess(false); 
       // map through your data and push each item into the observableArray 
       $.map(response.Items, function (item) { 
        self.Items.push(new ItemDetailViewModel(item)); 
        }); 
       }else{ 
       // if there is no more data stop the interval function. 
       clearInterval(loadMoreTimer); 
       } 
      }       

     }) 
    } 
    //Call to start lazy loading 
    self.AutomaticLoadItem(); 
} 

var ItemDetailViewModel = function (data){ 
    var self = this ; 
    self.Id = data.Id ; 
    self.Name = data.Name; 
    // ..... 
}