长html绑定冻结浏览器

时间:2014-02-04 10:37:40

标签: javascript jquery html knockout.js

我正在使用KnockoutJs html属性绑定将一个大的html文档(~2兆)渲染成DIV元素,如下所示:

<div id="myDiv" data-bind="with: $root.myDocument">
     <div id="elementBody"  data-bind="html: body">
     </div>
</div>

效果很好,但是当用户浏览器冻结变得无法使用时,绑定时间大约需要3-4秒。

有没有办法让这个文件避免这个长的绑定时间?我可以逐步渲染吗?

我尝试了什么

我尝试使用此自定义绑定但似乎不是解决方案:

ko.bindingHandlers.appendText = {
    init: function (element, valueAccessor, allBindings) {

        var data = ko.utils.unwrapObservable(valueAccessor());

        var array = data.match(/.{1,1000}/g);

        $.each(array, function (i, val) {
            setTimeout(function () {
                $(element).append(array[i]);
            }, 5);
        });
    }
};

它会中断标记,并且在.each循环结束之前文档不可见。

1 个答案:

答案 0 :(得分:4)

原则上,你的setTimeout技术有助于让DOM有时间在添加HTML标记之间呈现内容。但是,为了利用此功能,您的绑定编写不正确:

    $.each(array, function (i, val) {
        setTimeout(function () {
            $(element).append(array[i]);
        }, 5);
    });

这样做,它'同步'循环遍历所有数组项,并同时添加不同的setTimeout调用。你可能想做的是做第一个追加,然后用setTimeout做第二个追加,然后用setTimeout做第三个追加等等。

// replacing your foreach loop
var $element = $(element),
    appendItem = function (index) {
        if (index < array.length) {
            $(element).append(array[index]);
            setTimeout(function () {
                appendItem(++index);
            }, 1);
        });
    };
appendItem(0);

这应该在添加徽章之间触发渲染(没有测试代码,如果有错误就很抱歉)。但是,如果你从开始到结束测量它,这可能会使整个过程变得更慢,因为现在(可能)会有一个DOM重绘的BUNCH。你可以尝试一下。

真正的问题是,你能期待什么? 2 MB的DOM内容很多。我想知道你最终能有多快获得它。

可能会或可能不会改善渲染时间的另一个提示:在使用我提出的修复时,在渲染时将使用自定义绑定的元素设置为display: none。该修复程序应该有助于保持dom(有点)响应,但大多数浏览器将在不显示正在更改的元素时优化DOM重排。如果这样做,你可以否定我之前提到的批量附加的额外性能损失。