javascript - 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">
解决方案
我不认为淘汰订阅支持异步读取方法。您可以使用可观察的支持您的计算来代替:
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()" />
推荐阅读
- python - django 静态文件 - 404
- compiler-errors - rtorrent 编译错误:错误:#include 需要“文件名”或
- python - 没有返回的递归函数不断循环?
- python - 将 PyTorch 模型 state_dict 保存到 redis 缓存中
- json - json数组转换为formdata变成字符串
- python - Matplotlib:双轴上的网格线?
- python - 如何使用 python 将我的置信度数限制为小数点后两位?
- django - Django ManyToMany关系,modelmultiplechoicefield的过滤选项
- go - 似乎无法开始使用 Go 和 Echo
- php - 具有变体标准的徽章系统,数据库设计