链接可观察对象

Chaining observables

我知道这个问题已经被问过几次了,但我找不到在 Angular 5 with rxjs5 中实际工作的解决方案。

TL;DR; 如何按顺序同步将这 4 个 observables 设为 运行:

    const getImage$ = this.fileService.getImage(this.shape.imageFile.id);
    const getUrl$ = Observable.create((blob: Blob) => {
        return URL.createObjectURL(blob);
    });
    const fromURL$ = Observable.bindCallback(fabric.Image.fromURL);
    const addImage$ = Observable.create((img: any) => {
        this.shapeElement = img;
        this.shapeGroup = new fabric.Group([this.shapeElement], {
            lockScalingFlip: true,
            centeredRotation: true,
            angle: this.shape.rotation
        });
        this.fabric.add(this.shapeGroup);
    } );

然后是 return Observable,这样我就可以在订阅者中做更多的事情。

更长的版本...

我有一个请求图像的文件服务,returns 是 blob 的可观察对象:

getImage(id) => Observable<Blob>

然后我需要获取此 blob 的 url:

URL.createObjectURL(blob)

然后我需要将它加载到 FabricJS canvas,它有一个带回调的函数。我从中创建并观察到:

fromURL = Observable.bindCallback(fabric.Image.fromURL)

最后,我需要 fiddle 在 return observable 之前使用 Fabric 创建的图像对象 - 订阅有更多内容来更新 ui。

this.shapeGroup = new fabric.Group([this.shapeElement], {
   lockScalingFlip: true,
   centeredRotation: true,
   angle: this.shape.rotation,
   tag: Date.now()
  });
this.shapeGroup.shapeView = this;
this.shapeGroup.setShadow(this.getShadow());
this.canvas.fabric.add(this.shapeGroup);

这是我迷路的地方。我试图了解 mergeMap 和 map 和 pipe 以及其他一些东西,但我无法让它工作。

这里有人做过这种事吗?这看起来确实过于复杂。

我已经开始了:

draw(): Observable<ImageView> {  

  const fromURLOb = Observable.bindCallback(fabric.Image.fromURL);

  return Observable.create(o => {
    if (this.shape.imageFile) {
      console.log('started loading');               
      o.next(this.fileService.getImage(this.shape.imageFile.id));
    }
    o.complete();
  })
 ...

有效,但我迷路了。

解决方法!

感谢@Ingo,这是我的工作版本。

    draw(): Observable<ImageView> {
      return this.fileService.getImage(this.shape.imageFile.id)
        .map(blob => URL.createObjectURL(blob))
        .switchMap<string, any>(url => {
            return Observable.bindCallback(fabric.Image.fromURL).call(this, url);
        })
        .do<ImageView>(image => {
            this.handleImage(image);
            return this;
        });
}

这里发生了一些事情:

  1. URL.createObjectURL 实际上只是一个同步函数,它不是 return 可观察的。因此,您只需使用 map 将结果从 getImage 映射到 URL.
  2. fromUrl 调用确实使用了回调,因此您可以像以前一样使用 bindCallback;但是,bindCallback 不是 return 可观察值(正如您指出的那样),而是 return 是一个 return 可观察值的函数。所以你需要用你得到的 URL 调用那个函数;您可以在此处的链中使用 switchMap 或其变体之一;由于您只处理 "emits once and completes" 个可观察对象,因此这些变体之间的差异并不重要。
  3. 你所做的最后处理实际上只是一个副作用,它不会影响你想要 return 的值,因此你可以只使用 do 运算符来执行副作用.
  4. 您对 Observable.create 的用法表明存在一些误解。传递给 Observable.create always 的函数接收一个观察者作为参数,而不是某个值。我认为您在这里混淆了函数和可观察对象。

因此,您可以这样做:

private handleImage(img: any) {
    this.shapeElement = img;
    this.shapeGroup = new fabric.Group([this.shapeElement], {
        lockScalingFlip: true,
        centeredRotation: true,
        angle: this.shape.rotation
    });

    this.fabric.add(this.shapeGroup);
}

draw() {
  return this.fileService.getImage(this.shape.imageFile.id)
    .map(blob => URL.createObjectURL(blob))
    .switchMap(url => Observable.bindCallback(fabric.Image.fromURL)(url))
    .do(image => this.handleImage(image));
}