javascript - Force Knockout 计算以在替换 observable 内部后重新评估
问题描述
一位同事遇到了一个问题,即他想要测试的计算机没有返回预期的输出。发生这种情况是因为我们想要存根其他计算(再次依赖于其他计算)。存根之后,计算中剩下 0 个可观察对象,并且计算不断返回缓存的结果。
我们如何强制计算重新评估其中不再有原始可观察对象?
const ViewModel = function() {
this.otherComputed = ko.computed(() => true);
this.computedUnderTest = ko.computed(() => this.otherComputed());
};
const vm = new ViewModel();
function expect(expected) {
console.log(vm.computedUnderTest() === expected);
}
// Init
expect(true);
// Stub dependent computed
vm.otherComputed = () => false;
// Computed no longer receives updates :(
expect(false);
// Can we force re-evaluation?
// vm.computedUnderTest.forceReEval()
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
解决方案
我能想到的唯一不涉及更改代码的解决方案ViewModel
是先存根ko.computed
...
在下面的示例中,我替换ko.computed
为扩展版本。该扩展公开了一个属性,.stub
允许您编写自定义函数。设置此功能后,计算将使用提供的逻辑重新评估。
在您的测试文件中,您需要能够在实例化 ViewModel 实例之前ko.computed
替换准备代码中的全局引用。
// Extender that allows us to change a computed's main value getter
// method *after* creation
ko.extenders.canBeStubbed = (target, value) => {
if (!value) return target;
const stub = ko.observable(null);
const comp = ko.pureComputed(() => {
const fn = stub();
return fn ? fn() : target();
});
comp.stub = stub;
return comp;
}
// Mess with the default to ensure we always extend
const { computed } = ko;
ko.computed = (...args) =>
computed(...args).extend({ canBeStubbed: true });
// Create the view model with changed computed refs
const ViewModel = function() {
this.otherComputed = ko.computed(() => true);
this.computedUnderTest = ko.computed(() => this.otherComputed());
};
const vm = new ViewModel();
function expect(expected) {
console.log("Test succeeded:", vm.computedUnderTest() === expected);
}
expect(true);
// Replace the `otherComputed`'s code by another function
vm.otherComputed.stub(() => false);
expect(false);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
在我自己的项目中,我倾向于使用一种完全不同的方法来测试我的计算结果,该方法侧重于将逻辑与依赖项分开。如果上面的示例不适合您,请告诉我。(如果这已经满足您的需求,我不会写另一个答案)
推荐阅读
- c# - 在父方法中使用子属性
- javascript - 数组中的值如何随 Jquery 移动?
- sas - 从数值到时间值
- ios - SWIFT ABI 在哪里发挥作用?
- c - exec,execvp,execl,execv之间的区别?
- movesense - 无法在 movesense 设备上写入 EEPROM
- amp-html - 我需要将 onclick 函数重写为可以为 Google AMP 处理的代码
- popup - 如何在鼠标悬停和单击时在 OpenLayers 5 中实现功能弹出窗口
- performance - Maria DB INDEX selection - 为什么 maria 选择次优索引?
- php - 在 Wordpress 的搜索查询中搜索并匹配一个或多个单词