[英]Chain joined observables to one subscription
I've got a model class called 'Item' which needs two seperate images to be loaded from the backend (a sprite-texture and a shadow-texture to be precise). 我有一个名为“ Item”的模型类,该类需要从后端加载两个单独的图像(准确地说是sprite纹理和shadow纹理)。 I achieved a parallel loading and eventual join of the textures into my Item so that I could simply subscribe to it in another place.
我实现了并行加载并最终将纹理连接到我的Item中,因此我可以在另一个地方简单地订阅它。
Now, I've had this working when I used Base64 to transfer the files to my Angular2 Application. 现在,当我使用Base64将文件传输到我的Angular2应用程序时,我已经完成了这项工作。 But now I want to work with the plain blobs.
但是现在我想使用普通Blob。 Although this is not yet supported by Angular2, it is totally possible to read the private _body property of the response.
尽管Angular2尚不支持此功能,但完全有可能读取响应的private _body属性。 The thing is that my model class should retrieve the images as
HTMLImageElements
with the data parsed as a Base64 data url. 关键是我的模型类应该将图像检索为
HTMLImageElements
,并将数据解析为Base64数据url。 To generate this data url from my blobs I need to use FileReader.readAsDataUrl()
which works based on a callback. 要从我的Blob生成此数据url,我需要使用
FileReader.readAsDataUrl()
,它基于回调工作。 I think I've figured out how to wrap this callback into an Observable (correct me if this approach is wrong, as I can't confirm it at this point). 我想我已经弄清楚了如何将该回调包装到一个Observable中(如果这种方法不正确,请纠正我,因为我目前无法确认)。
So, now I simply can not figure out how to correctly chain my calls to be able to subscribe to a resulting Observable which then produce my Item, like this ItemService.getItem(1).subscribe(item => ...)
因此,现在我根本无法弄清楚如何正确地链接我的调用以能够订阅生成的Observable,然后生成我的Item,例如
ItemService.getItem(1).subscribe(item => ...)
The current setup gives me a weird error stating that the subscribe-method is not defined on the resulting Observable. 当前设置给我一个奇怪的错误,指出未在生成的Observable上定义订阅方法。 Im pretty new to RxJS and would be very glad if someone could show me how to set this up properly :)
我对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
})
}
The problem is two-fold. 问题是双重的。 First is that
bindCallback
returns a function which returns an Observable
when invoked it does not return an Observable
. 首先是
bindCallback
返回一个函数 ,该函数在调用时返回Observable
,但不返回Observable
。 The idea of binding a callback is that you are converting a function that normally reports its async result through a callback into an Observable
. 绑定回调的想法是,您正在将通常通过回调报告其异步结果的函数转换为
Observable
。
In this case you are actually waiting on an event to be fired ( loadend
), so you likely want to use fromEvent
instead. 在这种情况下,您实际上正在等待要触发的事件(
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();
}
Now this isn't terribly robust but should get the job done. 现在,这并不是十分强大,但是应该可以完成工作。 If you want to see a more complete example there is a
fromReader
method that was written for RxJS4 that you could commandeer for your purposes (the version for RxJ5 hasn't been implemented yet). 如果要查看更完整的示例,可以为
fromReader
编写一个fromReader
方法,您可以根据自己的目的进行命令(RxJ5的版本尚未实现)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.