【问题标题】:Chain joined observables to one subscription链将 observables 加入到一个订阅中
【发布时间】:2016-07-29 03:45:12
【问题描述】:

我有一个名为“Item”的模型类,它需要从后端加载两个单独的图像(准确地说是精灵纹理和阴影纹理)。我实现了纹理的并行加载并最终将纹理连接到我的项目中,这样我就可以在另一个地方简单地订阅它。

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

所以,现在我根本无法弄清楚如何正确链接我的调用,以便能够订阅生成的 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
    })
}

【问题讨论】:

    标签: typescript angular rxjs


    【解决方案1】:

    问题有两个方面。首先是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 的版本尚未实现)。

    【讨论】:

    • 谢谢,图像现在解析正确,但是第二个fork-join的选择器(从事件创建的observable)没有被调用,你知道为什么吗?我使用的 flatMap 调用是否正确?
    • 啊,是的,问题是forkJoin 等到源完成后再发出,fromEvent 没有完成,所以你需要添加 firsttake(1) 到它.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    相关资源
    最近更新 更多