使用knockout绑定约5000条记录

时间:2014-07-23 13:48:50

标签: knockout.js durandal ko.observablearray

我试图使用knockout observable数组在网页中显示大约5000条记录,这需要花费很多时间,

有没有办法在没有分页的情况下处理这个问题?

请帮助..

视图模型中的JS代码,数据来自gridData源中的ajax调用:

 groupGrid.prototype.updateGrid = function (gridDataSource, groupGridOptions) {
        var self = this;
        self.ColumnName(groupGridOption.ColumnNameList); //   List of column name available in the data source.
        self.gridData(gridDataSource);    //  taking time while executing this code  
        self.totalRowCount(self.gridData().length);
        self.selectedItems.removeAll();
        self.selectedRowCount(0);
    };

HTML代码:

<tbody class="ngTBody" data-bind="foreach: gridData">
<tr class="ngdatarow">
<td>
    <span class="nameHeader" data-bind="text: $data[$root.ColumnName()[0]], click: $root.gridNameClick" style="cursor: pointer; text-decoration: underline"></span>
</td>
<td>
    <span class="displayBlock" data-bind="text: $data[$root.ColumnName()[1]]"></span>
</td>
<td>
    <span class="displayBlock" data-bind="text: $data[$root.ColumnName()[3]"></span>
</td>
</tr>
</tbody>

2 个答案:

答案 0 :(得分:5)

我最近在我的KO应用程序中与性能有点摔跤。我刚刚在这里添加了另一个问题的答案,并提出了一些想法:

Knockout subscribe is blocking the page

由此产生的,这是一个小提琴,表明你不需要太多延迟 - 这个演示有3000个项目,并为每个项目生成一个简单的div。根据上面链接的博客文章,这些项目首先在JS数组中构建,然后再转换为observableArray。所以我很确定在这个阶段你看到的性能问题很简单就是由KO的工作引起的DOM操作。

http://jsfiddle.net/HBYyL/1/

这并不能解决性能问题,但是如果你循环遍历数千个项目并且它使用的模式可以确保在长时间之前出现加载微调器,则表明延迟可能是不可避免的。 KO操作,然后隐藏它。所以它至少改善了用户体验。

确保您可以加载微调器:

// Show the spinner immediately...
$("#spinner").show();

// ... by using a timeout.
window.setTimeout(function() {
    ko.applyBindings(vm)  
}, 1)

隐藏微调器:

<div data-bind="template: {afterRender: hide}">

更新1:

我记得当我使用Opera在机顶盒上工作时,使用DOM操作构建UI时的旧技术。它的速度令人震惊,因此解决方案是将大块HTML存储为字符串,并通过设置innerHTML属性来加载字符串。单页应用的早期版本。无论如何,作为我在这个区域进行的摆弄的一部分,这里有一个jsfiddle显示通过KO加载的5000个项目,但通过计算的中间html。

http://jsfiddle.net/9ZF3g/1/

换句话说,您从列表中计算HTML,并使用html绑定一次性设置它。我已将此示例设置为5000个项目,几乎是即时的。

严重的缺点是它严重限制了你在每个项目内绑定所能做的事情......


更新2:

这是一个小提琴,显示了通过数组索引从项目链接到KO视图模型的一些外观。你可以使用像这样的结构来做KO支持的大部分工作,但是你会失去一些魔力;我认为你必须自己编写更多的代码。

http://jsfiddle.net/9ZF3g/2/


更新3:

这个小提琴显示了一种使用超时将每个项目逐个推入列表的技术。通过在推送操作之间设置超时,DOM逐项更新。因此整体渲染时间仍然很长,但用户可以立即获得反馈:

http://jsfiddle.net/rosenfeld/7TwcV/1/


更新4:

展示上述技巧,但通过删除记录做一些有用的事情。

http://jsfiddle.net/9ZF3g/3/

答案 1 :(得分:5)

我已经在浏览器中快速生成数据表进行了大量研究。使用foreachtext绑定的标准Knockout方法非常慢。正如我的Repeat binding所示,简化绑定代码可以实现一些改进。但生成数据表的最快方法是将其组合为JavaScript代码中的字符串,然后使用innerHTML将其插入DOM中。我的Table binding就是如何做到这一点的一个例子。

在您的情况下,组装数据表的自定义绑定将提供巨大的速度提升。这是我根据你的例子放在一起的自定义绑定:

ko.bindingHandlers.myDataTable = {
    init: function () {
        return { controlsDescendantBindings: true };
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var output = [],
            value = valueAccessor(),
            columns = ko.unwrap(value.columns),
            column1 = columns[0],
            column2 = columns[1],
            column3 = columns[2],
            data = ko.unwrap(value.data),
            dataLength = data.length,
            clickFunction = value.click;
        output.push('<table><tbody class="ngTBody">');
        for (var i = 0; i < dataLength; ++i) {
            output.push('<tr class="ngdatarow"><td><span class="nameHeader" data-index="');
            output.push(i + '">');
            output.push(data[i][column1]);
            output.push('</span></td><td><span class="displayBlock">');
            output.push(data[i][column2]);
            output.push('</span></td><td><span class="displayBlock">');
            output.push(data[i][column3]);
            output.push('</span></td></tr>');
        }
        output.push('</tbody></table>');
        element.innerHTML = output.join('');
        $(element).on('click', 'span.nameHeader', function (event) {
            var index = event.target.getAttribute('data-index');
            if (index) {
                clickFunction(data[index], event);
            }
        });
    }
};

为了比较,我把以下两个小提琴放在一起:

  1. http://jsfiddle.net/mbest/csP6k/使用foreach。在我的计算机上渲染表需要2到3秒钟。
  2. http://jsfiddle.net/mbest/8cKuP/使用自定义绑定。渲染表格的速度快了近25倍。
  3. 我还创建了example,其中包含click个绑定并使用ko.applyBindingsToDescendants,但它需要比上面的示例更长的时间,因为它必须设置5000个事件处理程序而不是一个。