【问题标题】:Chaining observables链接 observables
【发布时间】:2018-03-29 17:34:05
【问题描述】:

我知道这个问题已经被问过几次了,但我找不到在 Angular 5 和 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);
    } );

然后返回 Observable,以便我可以在订阅者中做更多事情。

更长的版本...

我有一个文件服务请求图像并返回 blob 的 observable:

getImage(id) => Observable<Blob>

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

URL.createObjectURL(blob)

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

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

最后,在我返回 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;
        });
}

【问题讨论】:

    标签: fabricjs angular5 rxjs5


    【解决方案1】:

    这里发生了一些事情:

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

    因此,您可以这样做:

    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));
    }
    

    【讨论】:

    • 谢谢! Observable.bindCallback(fabric.Image.fromURL)(url) 告诉我 Expected 0 arguments, but got 1. :(
    • 啊,必须这样做:Observable.bindCallback(fabric.Image.fromURL).call(url) 因为 .fromURL 是一种对象方法,而不是本地乐趣。
    • 有效!你做到了!我已经坚持了好几天了。你喜欢啤酒还是巧克力? :):)(我在上面更新了最终工作版本)
    • 很高兴它成功了。小提示:do 中的return this 是不必要的。副作用不会返回任何内容。
    猜你喜欢
    • 2018-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-09-07
    相关资源
    最近更新 更多