一次更改多个可观察对象时提高淘汰赛性能
Improve knockout performance when changing multiple observables at once
对于所提供的 JSFiddle 中 "click" 事件的任何性能建议,我将不胜感激。
这个想法是为了在一次更改多个 observable 时提高性能。
我找不到任何关于以批处理方式暂停和恢复更新通知的文档。
$("#all").click(function(){
var tasks = ko.dataFor($("#tasks")[0]).tasks(),
checked = this.checked;
//TODO: performance? Batch changes?
for(var i = 0, l = tasks.length; i<l; i++){
tasks[i].done( !!checked );
}
});
专注于有效的优雅解决方案通常是个好主意,并且仅在遇到性能问题时进行优化,或者至少合理地预期特定代码片段会成为瓶颈。
本着这种精神,我编写了一个解决方案,使“全部”复选框的响应速度更快一些:
- 如果所有的任务框都被选中,则全部被选中
- 如果选中了所有任务框而未选中任务框,则将取消选中所有任务
- 选中全部会导致选中所有任务框
- 取消选中全部会导致取消选中所有任务框
没有点击事件处理,也没有使用 jQuery。尽管每次值更改时这都会贯穿任务项,但我认为您可以有一百个任务框并且没有明显的性能问题。
var viewModel = ko.mapping.fromJS({
tasks: [{
name: "Task 1",
done: false
},{
name: "Task 2",
done: true
},{
name: "Task 3",
done: false
}]
});
viewModel.allChecked = ko.computed({
read: function () {
var tasks = viewModel.tasks();
for (var i=0; i<tasks.length; ++i) {
if (!tasks[i].done()) {
console.debug("Nope");
return false;
}
}
return true;
},
write: function (newValue) {
var tasks = viewModel.tasks();
for (var i=0; i<tasks.length; ++i) {
tasks[i].done(newValue);
}
}
});
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdn.rawgit.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<label>All</label>
<input id="all" type="checkbox" data-bind="checked:allChecked" />
<br><br><br>
<div id="tasks" data-bind="foreach: tasks">
<label data-bind="text: name"></label>
<input type="checkbox" data-bind="checked: done" />
</div>
您可以更改模型以跟踪已检查任务的集合,而不是直接指示已检查哪些任务。它应该使实现更容易和更快,因为只有一个 observable 会被更新。只需创建一个(可观察的)数组并将 checked
绑定到该数组。还要确保 value
已绑定。
<div id="tasks" data-bind="foreach: tasks">
<label data-bind="text: name"></label>
<input type="checkbox" data-bind="checked: $parent.checkedTasks, value: $data" />
</div>
var data = {
tasks: [{
name: "Task 1"
},{
name: "Task 2"
},{
name: "Task 3"
}]
};
ko.applyBindings( ko.mapping.fromJS(data, {}, {
checkedTasks: ko.observableArray([])
}), $("#tasks")[0]);
$("#all").click(function(){
var model = ko.dataFor($("#tasks")[0]),
checked = this.checked;
if (checked) {
model.checkedTasks(model.tasks().slice(0));
} else {
model.checkedTasks([]);
}
});
对于所提供的 JSFiddle 中 "click" 事件的任何性能建议,我将不胜感激。
这个想法是为了在一次更改多个 observable 时提高性能。
我找不到任何关于以批处理方式暂停和恢复更新通知的文档。
$("#all").click(function(){
var tasks = ko.dataFor($("#tasks")[0]).tasks(),
checked = this.checked;
//TODO: performance? Batch changes?
for(var i = 0, l = tasks.length; i<l; i++){
tasks[i].done( !!checked );
}
});
专注于有效的优雅解决方案通常是个好主意,并且仅在遇到性能问题时进行优化,或者至少合理地预期特定代码片段会成为瓶颈。
本着这种精神,我编写了一个解决方案,使“全部”复选框的响应速度更快一些:
- 如果所有的任务框都被选中,则全部被选中
- 如果选中了所有任务框而未选中任务框,则将取消选中所有任务
- 选中全部会导致选中所有任务框
- 取消选中全部会导致取消选中所有任务框
没有点击事件处理,也没有使用 jQuery。尽管每次值更改时这都会贯穿任务项,但我认为您可以有一百个任务框并且没有明显的性能问题。
var viewModel = ko.mapping.fromJS({
tasks: [{
name: "Task 1",
done: false
},{
name: "Task 2",
done: true
},{
name: "Task 3",
done: false
}]
});
viewModel.allChecked = ko.computed({
read: function () {
var tasks = viewModel.tasks();
for (var i=0; i<tasks.length; ++i) {
if (!tasks[i].done()) {
console.debug("Nope");
return false;
}
}
return true;
},
write: function (newValue) {
var tasks = viewModel.tasks();
for (var i=0; i<tasks.length; ++i) {
tasks[i].done(newValue);
}
}
});
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdn.rawgit.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.js"></script>
<label>All</label>
<input id="all" type="checkbox" data-bind="checked:allChecked" />
<br><br><br>
<div id="tasks" data-bind="foreach: tasks">
<label data-bind="text: name"></label>
<input type="checkbox" data-bind="checked: done" />
</div>
您可以更改模型以跟踪已检查任务的集合,而不是直接指示已检查哪些任务。它应该使实现更容易和更快,因为只有一个 observable 会被更新。只需创建一个(可观察的)数组并将 checked
绑定到该数组。还要确保 value
已绑定。
<div id="tasks" data-bind="foreach: tasks">
<label data-bind="text: name"></label>
<input type="checkbox" data-bind="checked: $parent.checkedTasks, value: $data" />
</div>
var data = {
tasks: [{
name: "Task 1"
},{
name: "Task 2"
},{
name: "Task 3"
}]
};
ko.applyBindings( ko.mapping.fromJS(data, {}, {
checkedTasks: ko.observableArray([])
}), $("#tasks")[0]);
$("#all").click(function(){
var model = ko.dataFor($("#tasks")[0]),
checked = this.checked;
if (checked) {
model.checkedTasks(model.tasks().slice(0));
} else {
model.checkedTasks([]);
}
});