2016-07-28 41 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