我正在使用 KnockoutJs
html 属性绑定(bind)将一个大的 html 文档(约 2 兆)渲染到 DIV
元素中,如下所示:
<div id="myDiv" data-bind="with: $root.myDocument">
<div id="elementBody" data-bind="html: body">
</div>
</div>
它工作得很好,但绑定(bind)时间大约需要 3-4 秒,同时用户浏览器卡住变得无法使用。
有没有办法渲染此文档,避免这么长的绑定(bind)时间?我可以逐步渲染它吗?
我尝试了什么
我尝试过这个自定义绑定(bind),但它似乎不是一个解决方案:
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
循环结束之前文档不可见。
最佳答案
原则上,您的 setTimeout 技术确实有助于为 DOM 提供时间来在添加 HTML 标记之间呈现内容。但是,您的绑定(bind)未正确编写以利用此功能:
$.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 重绘。不过你可以尝试一下。
真正的问题是,您能期待什么? 2 MB 的 DOM 内容已经很多了。我想知道你最终能多快得到它。
另一个可能会或可能不会缩短渲染时间的提示:在使用我建议的修复时,在渲染时将使用自定义绑定(bind)的元素设置为 display: none
。该修复应该有助于保持 dom (某种程度)响应,但大多数浏览器会在未显示正在更改的元素时优化 DOM 回流。如果这有效,您就可以消除我之前提到的批量附加的额外性能损失。
关于javascript - 长 html 绑定(bind)卡住浏览器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21550053/