我正在使用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
循环结束之前文档不可见。
答案 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重排。如果这样做,你可以否定我之前提到的批量附加的额外性能损失。