2016-08-12 29 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; 
    // ..... 
}