Typescript 击倒承诺约束
是否存在用于承诺的良好绑定实现?我尝试的每件事似乎最终都给了我一个错误,即无法将绑定多次应用于同一个元素(我理解这一点,并且正在尝试找到解决方法)。我发现了,但它已经相当旧了,而且似乎只适用于不控制后代绑定的绑定,原因与此相同 我还尝试编写自己的实现,试图删除子项,并在承诺解决后重新附加/绑定它们,但得到了相同的结果 另一种选择是,我可能创建一个异步计算的可观察对象进行绑定,但随后键入(我使用的是TypeScript)变得有点模糊,因为我将返回一个承诺,但从可观察对象读取的值将是其他值。我可以(有效地)将其键入“Promise | T”,但这可能会让人困惑,因为它实际上只会是“T” 编辑:这就是我说的打字问题。请记住,我正在使用一种方法将可观察对象隐藏在getter/setter后面,以便我的属性看起来像常规的javascript属性。我的想法是使用装饰器将返回承诺的getter转换为返回值的getterTypescript 击倒承诺约束,typescript,knockout.js,data-binding,promise,Typescript,Knockout.js,Data Binding,Promise,是否存在用于承诺的良好绑定实现?我尝试的每件事似乎最终都给了我一个错误,即无法将绑定多次应用于同一个元素(我理解这一点,并且正在尝试找到解决方法)。我发现了,但它已经相当旧了,而且似乎只适用于不控制后代绑定的绑定,原因与此相同 我还尝试编写自己的实现,试图删除子项,并在承诺解决后重新附加/绑定它们,但得到了相同的结果 另一种选择是,我可能创建一个异步计算的可观察对象进行绑定,但随后键入(我使用的是TypeScript)变得有点模糊,因为我将返回一个承诺,但从可观察对象读取的值将是其他值。我可以(
export class Foo {
@promise get bar(): int {
return new Promise<int>((resolve, reject) => {
setTimeout(() => { resolve(1) }, 100);
});
}
}
导出类Foo{
@promise get bar():int{
返回新承诺((解决、拒绝)=>{
setTimeout(()=>{resolve(1)},100);
});
}
}
这样做看起来不错,只是TypeScript会抱怨返回类型。我可以把它投给任何人,但那是不对的。或者,我可以将getter返回值转换为Promise | T,但这会歪曲实际的返回类型,因为它总是T
在绑定方面,我不希望重新绑定所有内容,但在像“if”绑定这样的情况下(这实际上是我正在尝试使用的),似乎并没有真正的解决方法
编辑2:以防万一,下面是我当前的“承诺”绑定处理程序化身:
import * as ko from "knockout";
ko.bindingHandlers["promise"] = {
init(element: HTMLElement, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
let first = true;
function apply(bindingName: string, val: any) {
ko.applyBindingsToNode(element, { [bindingName]: val }, bindingContext);
}
ko.computed(() => {
let bindings = ko.unwrap(valueAccessor());
if(bindings) {
ko.tasks.schedule(() => {
for(let bindingName in bindings) {
let promise = bindings[bindingName] as Promise<any>;
if(promise && promise.then) {
promise.then(val => {
apply(bindingName, val);
first = false;
});
} else {
apply(bindingName, bindings[bindingName]);
first = false;
}
}
});
}
}, null, { disposeWhenNodeIsRemoved: element })();
return {
controlsDescendantBindings: false
};
}
}
ko.virtualElements.allowedBindings["promise"] = true;
import*作为ko从“knockout”导入;
ko.bindingHandlers[“承诺”]={
init(元素:HtmleElement、valueAccessor、allBindingsAccessor、viewModel、bindingContext){
让第一个=真;
函数apply(bindingName:string,val:any){
applybindingstoode(元素,{[bindingName]:val},bindingContext);
}
ko.computed(()=>{
让bindings=ko.unwrap(valueAccessor());
如果(绑定){
ko.任务.时间表(()=>{
for(在绑定中使用bindingName){
让promise=bindings[bindingName]作为promise
其中,canAccessFoo、canAccessBar和canAccessFooBar是解析为布尔值的承诺。我想我找到了一个解决方案。关键是“ko.applyBindingsToNode”的返回值,它是一个具有单个属性“shouldBindingstands”的对象。applyBindingsToNode调用的返回值列为“any”在typescript声明中,所以我不知道其中包含什么,直到我好奇并记录下来。无论如何,这是绑定处理程序的当前版本(至少在我写这篇文章时是这样)
import*作为ko从“knockout”导入;
ko.bindingHandlers[“承诺”]={
init(元素:HTMLElement、valueAccessor、allBindingsAccessor、viewModel、bindingContext){
让bindings=ko.unwrap(valueAccessor());
函数apply(bindingName:string,val:any){
让result=ko.applybindingstoode(元素,{[bindingName]:val},bindingContext);
if(result.shouldBindDescents)ko.applyBindingsToDescents(bindingContext,元素);
}
如果(绑定){
for(在绑定中使用bindingName){
让promise=bindings[bindingName]作为promise;
if(promise&&promise.then){
承诺。然后(val=>{
apply(bindingName,val);
});
}否则{
应用(bindingName,bindings[bindingName]);
}
}
}
返回{
ControlsDescentBindings:true
}
}
}
ko.virtualElements.allowedBindings[“promise”]=true;
为什么要不止一次地应用绑定?您可以异步更新现有的观测值,只要您预先创建它们,而不是用新实例替换它们。我列出的选项之一是在事后更新观测值,但这会带来键入问题,可能会让后来的人感到困惑。您要做什么要完成什么?使用observable来保存viewmodel是可以的。请检查,否则我不太理解您提到的键入问题。为什么它必须返回承诺,而不是简单地更新强类型observable?您可以发布一些示例代码吗?
<ul class="nav navbar-nav">
<!-- ko promise: { if: canAccessFooBar } -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown">Foobar</a>
<ul class="dropdown-menu>
<!-- ko promise: { if: canAccessFoo } -->
<li>
<a href="/foo">Foo</a>
</li>
<!-- /ko -->
<!-- ko promise: { if: canAccessBar } -->
<li>
<a href="/bar">Bar</a>
</li>
<!-- /ko -->
</ul>
</li>
<!-- /ko -->
</ul>
import * as ko from "knockout";
ko.bindingHandlers["promise"] = {
init(element: HTMLElement, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
let bindings = ko.unwrap(valueAccessor());
function apply(bindingName: string, val: any) {
let result = ko.applyBindingsToNode(element, { [bindingName]: val }, bindingContext);
if(result.shouldBindDescendants) ko.applyBindingsToDescendants(bindingContext, element);
}
if(bindings) {
for(let bindingName in bindings) {
let promise = bindings[bindingName] as Promise<any>;
if(promise && promise.then) {
promise.then(val => {
apply(bindingName, val);
});
} else {
apply(bindingName, bindings[bindingName]);
}
}
}
return {
controlsDescendantBindings: true
}
}
}
ko.virtualElements.allowedBindings["promise"] = true;