2016-07-28 42 views
0

我有一个名为'Item'的模型类,需要从后端加载两个单独的图像(精确到精灵纹理和阴影纹理)。我实现了并行加载并将纹理最终加入到我的项目中,以便我可以在另一个地方简单地订阅它。链加入observables到一个订阅

现在,当我使用Base64将文件传输到我的Angular2应用程序时,我已经有了这个工作。但是现在我想和普通的blob一起工作。尽管Angular2尚不支持这种方式,但完全可以读取响应的private _body属性。问题是我的模型类应该检索图像为HTMLImageElements,并将数据解析为Base64数据网址。要从我的blob生成这个数据url,我需要使用基于回调工作的FileReader.readAsDataUrl()。我想我已经想出了如何将这个回调包装成一个Observable(如果这种方法是错误的,请纠正我,因为我现在无法确认它)。

所以,现在我根本无法弄清楚如何正确连锁我的电话,以便能够订阅导致可观察,然后产生我的项目,这样ItemService.getItem(1).subscribe(item => ...)

当前的设置给了我一个奇怪的错误,说明该订阅方法未在生成的Observable上定义。我很新的RxJS,并会非常高兴,如果有人能告诉我如何正确地设置此:)

/* implementation in ItemService */ 

getItem(id:number):Observable<Item> { 
    return Observable.forkJoin(// join both texture fetches 
     this.http.get('/api/items/' + id + '/sprite'), // fetch sprite texture 
     this.http.get('/api/items/' + id + '/shadow'), // fetch shadow texture 
     (spriteResponse, shadowResponse) => { 
      // transform responses into proper blobs 
      const spriteBlob = new Blob([spriteResponse._body], {type: 'image/png'}) 
      const shadowBlob = new Blob([shadowResponse._body], {type: 'image/png'}) 
      return [spriteBlob, shadowBlob] 
     }) 
     .flatMap(result => Observable.forkJoin(// chain with joined image generation (pretty sure this is wrong somehow) 
      ItemService.generateImage(result[0]), // parse spriteBlob to image 
      ItemService.generateImage(result[1]), // parse shadowBlob to image 
      (spriteImage, shadowImage) => { 
       // assemble model from images 
       const item = new Item() 
       item.setSprite(spriteImage) 
       item.setShadow(shadowImage) 
       return item 
      }) 
     ) 
} 

static generateImage(data:Blob):Observable<HTMLImageElement> { 
    const img = new Image() // create new HTML Image 
    const reader = new FileReader() // init file reader 
    reader.readAsDataURL(data) // transform blob to base64 data url 

    // create observable from callback (is this correct?) 
    return Observable.bindCallback(reader.onloadend,() => { 
     img.src = reader.result 
     return img 
    }) 
} 

回答

2

问题是双重的。首先是bindCallback返回一个函数,它调用时返回Observable它不返回Observable。绑定回调的想法是,您正在将通常通过回调报告其异步结果的函数转换为Observable

在这种情况下,您实际上正在等待发生的事件(loadend),因此您可能想用fromEvent代替。

static generateImage(data:Blob):Observable<HTMLImageElement> { 
    const reader = new FileReader() // init file reader 
    reader.readAsDataURL(data) // transform blob to base64 data url 

    // create observable from callback (is this correct?) 
    return Observable.fromEvent(reader, 'load', (e) => { 
     var img = new Image(); 
     img.src = reader.result; 
     return img; 
    }).first(); 
} 

现在这不是非常强大,但应该完成工作。如果你想看到一个更完整的例子,有一个为RxJS4编写的fromReader方法,你可以为你的目的而征用(RxJ5的版本尚未实现)。

+0

谢谢,图像现在被正确解析,但第二个fork-join的选择器(其中从事件创建的observable)被加入不会被调用,你知道为什么吗?我正在使用正确的方法调用flatMap吗? – nilo

+1

啊,是的,问题在于'forkJoin'等待源文件完成才发出,'fromEvent'没有完成,所以你需要添加'first'或'take(1)'。 – paulpdaniels