首页 > 解决方案 > 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>

标签: javascriptknockout.jsknockout-3.0

解决方案


我能想到的唯一涉及更改代码的解决方案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>

在我自己的项目中,我倾向于使用一种完全不同的方法来测试我的计算结果,该方法侧重于将逻辑与依赖项分开。如果上面的示例不适合您,请告诉我。(如果这已经满足您的需求,我不会写另一个答案)


推荐阅读