代码之家  ›  专栏  ›  技术社区  ›  BeetleJuice

角度4和RxJS 5:可观察。concat()行为异常

  •  2
  • BeetleJuice  · 技术社区  · 8 年前

    我的Angular 4/TypeScript 2.3服务有一个功能 build() 如果类属性未初始化,则会出错。我正在尝试建立一个更安全的版本-- safeBuild() 生成()

    export class BuildService {
      
      renderer:Renderer2; // must be set for build() below to work
      
      // emits the new Renderer2 when renderer is set
      private rendererSet$:BehaviorSubject<Renderer2> = new BehaviorSubject(null);
    
      /** Set renderer, and notify any listener */
      setRenderer(renderer:Renderer2){
        this.renderer = renderer;
        this.rendererSet$.next(renderer);
      }
    
      /** Returns a new DOM element. Requires renderer to be set */
      build(elemTag:string){
        // if renderer is not set, we can't proceed
        // why is this error thrown when safeBuild() is called?
        if (!this.renderer) 
          throw new Error('Renderer must be set before build() is run');
    
        return this.renderer.createElement(elemTag);
      }
    
      /**
       * A safe version of build(). Will wait until renderer is set
       * before attempting to call build (Asynchronous)
       */
      safeBuild(elemTag:string):Observable<any> {
        // inform user that renderer should be set
        // this warning is printed to the console as expected
        if (!this.renderer) 
          console.warn('The build will be delayed until setRenderer() is called');
    
        // Listen to rendererSet$, filter out the null output, and call build()
        // only once the renderer is set. Why does the error still get thrown?
        return Observable.concat(
          this.rendererSet$.filter(e=>!!e).take(1),
          Observable.of(this.build(elemTag))
        )
      }
    }
    

    我尝试这样构建(从另一个服务):

    this.buildService.safeBuild(elemTag).subscribe(...)
    

    警告:生成将延迟,直到调用setRenderer()

    错误:必须在运行build()之前设置渲染器

    我本以为会收到警告,但在我的应用程序的另一部分调用之前,什么都不会发生 setRenderer() subscribe() 将运行。

    为什么我看到了错误?

    2 回复  |  直到 5 年前
        1
  •  3
  •   cartant    8 年前

    问题是 this.build(elemTag) concat 可观察-在执行串联时不可观察。

    您可以使用 defer :

    import 'rxjs/add/observable/defer';
    
    ...
    return Observable.concat(
      this.rendererSet$.filter(e => !!e).take(1),
      Observable.defer(() => Observable.of(this.build(elemTag)))
    );
    

    或者,正如评论中指出的那样,使用 map

    return this.rendererSet$
      .filter(e => !!e)
      .take(1)
      .map(() => this.build(elemTag));
    
        2
  •  -1
  •   Bunyamin Coskuner    8 年前

    this.build 函数返回。由于尚未设置渲染器,因此下面的行会引发错误。确保你 呼叫 setRenderer 功能优先

    if (!this.renderer) 
        throw new Error('Renderer must be set before build() is run');
    

    return Observable.concat(
      this.rendererSet$.filter(e=>!!e).take(1),
      this.rendererSet$.asObservable().map(() => this.build(elemTag)) // this line will execute when there is a new value set to rendererSet
    )
    
    推荐文章