gpt4 book ai didi

javascript - knockout 订阅阻塞了页面

转载 作者:行者123 更新时间:2023-11-28 01:07:52 25 4
gpt4 key购买 nike

我有一个可观察数组,其计算值用于获取单选列表中当前选定的项目。

self.KOVehicle.SelectedPolicy = ko.computed(function () {
return ko.utils.arrayFirst(self.KOVehicle.VehicleDetailsList(), function (veh) { return veh.PolicyId() == self.KOVehicle.SelectedPolicyId(); });
}, self);

我正在订阅更改,这将更新页面上的十几个不同的绑定(bind)项目。

self.KOVehicle.SelectedPolicy.subscribe(function (selectedPolicy) {
// show ajax loading spinner and do changes
});

现在一切正常了,除了在进行更改时似乎会阻塞页面。除非我打开 js 调试器并单步执行它,否则我看不到 ajax 加载旋转器。有什么想法吗?

最佳答案

我想我也遇到过同样的问题。在我当前的 KO 应用程序中,用户可以单击项目上的编辑。我加载与该项目关联的属性列表。这会触发一些 ko.compulated 函数和带有大量嵌套 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 完成后才会出现:

http://jsfiddle.net/6f6Rt/3/

我最初的答案建议使用超时作为解决方案,但我仍然找不到更好的方法。这是一个显示超时并使用计算值的 fiddle :

http://jsfiddle.net/222CG/2/

这是超时技巧:

// 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)

在这个 fiddle 中,如果你放一个

console.log("computing")

在计算内部,您会看到它被计算了 3001 次,最初一次,对于我们插入 vm.items() 的每个项目计算一次。在阅读有关提高应用程序性能的内容时,我遇到了 throttle :

http://knockoutjs.com/documentation/throttle-extender.html

这是一个显示计算节流的 fiddle ;还带有控制台输出;现在您可以看到它只被调用了两次,这一定值得边际性能增益!

http://jsfiddle.net/M4CUq/1/

就我的代码而言,它部署到平板电脑上,速度甚至更慢,尤其是在 CPU 速度较慢的旧 Android 上,所以我得出的结论是我确实应该优化它。我有嵌套的 for-each 循环,都在列表上工作,所以本质上我遇到了 O(n^2) 问题。我重写了列表数据结构,以便通过单个 foreach 循环即可实现我的目标。我把 2-3 秒的延迟减少到了不到半秒。

结论是:

  • 我怀疑你做错了什么根本上的错误;但使用 Knockout 可以触发一组可持续数秒的同步操作,特别是如果它包括 DOM 操作。这可以在上面的 fiddle 中看到,它使用一个简单的模板,但是一个大循环,阻塞页面约 3 秒,

  • 您能做的最好的事情就是尝试优化渲染代码并限制一些计算

  • 为了帮助改善用户体验,您可以使用超时技巧来确保在触发长 KO 操作之前旋转器可见

哦,最后...当一切都完成后,如何隐藏微调器?我决定使用模板绑定(bind)的 afterRender 回调,您可以在没有模板本身的情况下完成此操作,因此这里是显示操作中的最终 fiddle !

http://jsfiddle.net/A5tZU/

<小时/>

略有不同的方法 1:持续阅读 -

这个 fiddle 展示了一种使用超时将每个项目逐一插入列表的技术。通过在推送操作之间设置超时,DOM 会逐项更新。因此整体渲染时间仍然相当长,但用户会立即得到反馈:

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

<小时/>

略有不同的方法 2:另一个问题 -

我刚刚回答了另一个问题,其中我尝试了一个innerHTML技巧来极大地提高渲染大型列表的性能。

Binding around 5000 records using knockout

关于javascript - knockout 订阅阻塞了页面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24856219/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com