KnockoutJS 从 pureComputed 返回一个承诺

KnockoutJS returning a promise from pureComputed

我有一个 pureComputed 函数,我想在其中解决一个承诺,但是,当在模板中引用 promotionPrice 时,它显示未解决的承诺 ([object Promise])。我哪里出错了?调试后,我觉得我在代码中正确地解决了承诺...

    this.promotionPrice = ko.pureComputed({
        read: async () => {
            const regionPrice = this.getRegionPrices().then(regions => _.meanBy(regions, region => region.price));
            return await regionPrice;
        },
        write: (newValue) => {
            // Relevant write code here
        }
    }).extend({ notify: 'always' });

在 HTML 模板中...

<input type="text" class="form-control spaced-select" data-bind="value: promotionPrice">

我认为淘汰订阅者不支持异步读取方法。您可以使用可观察的支持您的计算来写入:

const val = ko.observable("loading");
const fetchedWhenNeeded = ko.pureComputed({
  read: function() {
    someApiCall().then(val);
    return val();
  }
});

ko.applyBindings({ fetchedWhenNeeded });

function someApiCall () {
  return new Promise(
    (res, rej) => {
      setTimeout(() => res(42), 750)
    }
  );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<h1 data-bind="text: fetchedWhenNeeded"></h1>

将此代码隔离到帮助程序中并考虑错误处理可能是值得的。例如:

const ObsFromAsyncGetter = (getDataAsync, initialValue = null) => {
  let triggered = false;
  const value = ko.observable(initialValue);
  
  return ko.pureComputed({
    read: () => {
      if (!triggered) {
        getDataAsync().then(value); // TODO: how will you handle errors?
        triggered = true;
      }
      
      return value();
    }
  });
}


const myValue = ObsFromAsyncGetter(someApiCall, "loading...");
console.log("Observable constructed");

// Note: API call is not yet made because nothing needs myValue
console.log("Applying bindings");
ko.applyBindings({ myValue });

// Note: API call only triggers once, even though it has three dependencies
console.log("Applied bindings");


function someApiCall () {
  console.log("API call made");
  return new Promise(
    (res, rej) => {
      setTimeout(() => res(42), 750)
    }
  );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<h1 data-bind="text: myValue"></h1>
<h2 data-bind="text: myValue"></h2>

如果你问这个问题的原因并不是基于淘汰依赖项延迟获取数据,而是更多关于管理服务器和客户端状态,我认为你最好创建两个普通的可观察对象并执行在您的视图模型中进行初始提取。类似于:

JS

const loading = ko.observable(true);
const serverState = ko.observable(null);
const clientState = ko.observable("");

const updateStateWithServerData = data => {
  serverState(data);
  clientState(data);
};

// Init
fetchData()
  .then(updateStateWithServerData)
  .finally(() => loading(false));

// Update after typing
clientState.subscribe(newValue => {
  loading(true);
  postData(newValue)
    .then(updateStateWithServerData)
    .finally(() => loading(false));
});

ko.applyBindings({ clientState, loading });

HTML:

<input data-bind="value: clientState, enable: !loading()" />