我有一个带有计算的可观察数组,用于获取当前所选的无线电列表项。
self.KOVehicle.SelectedPolicy = ko.computed(function () {
return ko.utils.arrayFirst(self.KOVehicle.VehicleDetailsList(), function (veh) { return veh.PolicyId() == self.KOVehicle.SelectedPolicyId(); });
}, self);
我正在订阅更改内容,这些内容将更新页面上的十几个绑定项目。
self.KOVehicle.SelectedPolicy.subscribe(function (selectedPolicy) {
// show ajax loading spinner and do changes
});
现在一切正常,除了它在进行更改时似乎阻止了页面。我没有看到ajax加载微调器,除非我打开js调试器并逐步执行它。有什么想法吗?
答案 0 :(得分:1)
我想我也遇到过同样的问题。在我当前的KO应用程序中,用户可以单击项目上的编辑。我加载了与该项关联的属性列表。这会触发一些ko.computed函数和一个包含大量嵌套foreach语句的大型KO模板。 KO同步评估所有这些,这意味着它必须在JavaScript解释器返回到我的代码的下一行之前完成。我低效的foreach循环中的DOM操作需要2-3秒,这就创建了页面“阻塞”大约2-3秒的外观,正如您所描述的那样。
这是一个非常简短的问题,作为HTML和JS的混合:
<button data-bind="click: edit">Edit</button>
// This is my list of attributes. A lot of computeds and a big template depend on
// this observable.
var list = ko.observableArray();
edit: function(data, event) {
// Update the list
list(data.list)
// Now wait 2-3 seconds for anything to happen.
}
为了给用户一些即时反馈,我尝试添加一个加载微调器,松散地:
<button data-bind="click: edit">Edit</button>
// This is my list of attributes. A lot of computeds and a big template depend on
// this observable.
var list = ko.observableArray();
edit: function(data, event) {
// Update the list
list(data.list)
$(".spinner").show() // Doesn't appear.
// Now wait 2-3 seconds for anything to happen. The spinner only then appears.
}
好的,显然我觉得我可以通过交换线来修复它:
<button data-bind="click: edit">Edit</button>
// This is my list of attributes. A lot of computeds and a big template depend on
// this observable.
var list = ko.observableArray();
edit: function(data, event) {
$("#spinner").show() // Still doesn't appear
// Update the list
list(data.list) // Blocks page
// Now wait 2-3 seconds for anything to happen.
}
这仍然不起作用 - 直到渲染完成后才会出现微调器。这是一个jsfiddle,正好展示了这个问题。您可以看到页面“阻止”的效果,因为按钮保持冻结在其活动状态,直到列表已呈现。直到KO完成之后,旋转器才会出现,即使我试图让它首先出现:
我的原始答案建议使用超时作为黑客来解决这个问题,但我仍然找不到更好的方法。这是一个小提示,显示超时并使用计算:
这是超时黑客:
// Show the spinner immediately...
$("#spinner").show();
// ... by using a timeout wrapped around the thing that causes the delay.
window.setTimeout(function() {
ko.applyBindings(vm)
}, 1)
在这个小提琴中,如果你放一个
console.log("computing")
在计算机内部,你会看到它计算3001次,一次最初,一次为每个项目我们推入vm.items()。在阅读有关改善我的应用程序性能的同时,我遇到了油门:
http://knockoutjs.com/documentation/throttle-extender.html
这是一个显示计算机油门的小提琴;还有控制台输出;现在你可以看到它只被调用了两次,这必然值得获得边际性能!
关于我的代码,它被部署到平板电脑上,它甚至更慢,尤其是在CPU速度慢的旧Androids上,所以我总结说我真的应该优化它。我已经嵌套了每个循环,都在列表上工作,所以基本上我有一个O(n ^ 2)问题。我重写了列表数据结构,以便我可以通过一个foreach循环实现我的目标。我将2-3秒的延迟降低到不到半秒。
总之:
我怀疑你做错了什么从根本上错误;但是Knockout可以触发一个可以持续几秒钟的同步操作集,特别是如果它包含DOM操作。这可以在上面的小提琴中看到,它使用一个简单的模板,但是一个大循环,阻止页面约3秒,
您可以做的最好的事情是尝试优化渲染代码并限制一些计算
并且为了帮助您使用UX,您可以使用超时黑客确保在触发长KO操作之前可以看到微调器
略有不同的方法1:持续阅读 -
这个小提琴显示了一种使用超时将每个项目逐个推入列表的技术。通过在推送操作之间设置超时,DOM逐项更新。因此整体渲染时间仍然很长,但用户可以立即获得反馈:
http://jsfiddle.net/rosenfeld/7TwcV/1/
略有不同的方法2:另一个问题 -
我刚刚回答了另一个问题,我尝试使用innerHTML技巧来大大提高渲染大型列表的性能。