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

标签: javascriptknockout.jspromiselodash

解决方案


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

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>

如果你问这个问题的原因不是真的关于基于淘汰依赖项懒惰地获取数据,而是更多关于管理服务器和客户端状态,我认为你可能会更好地创建两个普通的 observables 并在你的 viewmodel 中进行初始获取. 就像是:

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

推荐阅读