Typescript 击倒承诺约束

Typescript 击倒承诺约束,typescript,knockout.js,data-binding,promise,Typescript,Knockout.js,Data Binding,Promise,是否存在用于承诺的良好绑定实现?我尝试的每件事似乎最终都给了我一个错误,即无法将绑定多次应用于同一个元素(我理解这一点,并且正在尝试找到解决方法)。我发现了,但它已经相当旧了,而且似乎只适用于不控制后代绑定的绑定,原因与此相同 我还尝试编写自己的实现,试图删除子项,并在承诺解决后重新附加/绑定它们,但得到了相同的结果 另一种选择是,我可能创建一个异步计算的可观察对象进行绑定,但随后键入(我使用的是TypeScript)变得有点模糊,因为我将返回一个承诺,但从可观察对象读取的值将是其他值。我可以(

是否存在用于承诺的良好绑定实现?我尝试的每件事似乎最终都给了我一个错误,即无法将绑定多次应用于同一个元素(我理解这一点,并且正在尝试找到解决方法)。我发现了,但它已经相当旧了,而且似乎只适用于不控制后代绑定的绑定,原因与此相同

我还尝试编写自己的实现,试图删除子项,并在承诺解决后重新附加/绑定它们,但得到了相同的结果

另一种选择是,我可能创建一个异步计算的可观察对象进行绑定,但随后键入(我使用的是TypeScript)变得有点模糊,因为我将返回一个承诺,但从可观察对象读取的值将是其他值。我可以(有效地)将其键入“Promise | T”,但这可能会让人困惑,因为它实际上只会是“T”

编辑:这就是我说的打字问题。请记住,我正在使用一种方法将可观察对象隐藏在getter/setter后面,以便我的属性看起来像常规的javascript属性。我的想法是使用装饰器将返回承诺的getter转换为返回值的getter

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;