0

今天我在使用 RxJS 时看到了一个奇怪的问题。请帮我检查一下。

我正在处理的问题是:“给定一组图像 URL,将所有图像加载并附加到 div。”

要演示的所有代码片段都在这里:

https://pastebin.com/F3ZkH3F8

一开始,我使用the first snippet.

但是,Rx.Observable.prototype.flatMap有时会以错误的顺序排列图像(文档中注意到了这种行为)。所以,我改用concatMapsecond snippet)。

这一次,只加载了第一张图片。我花了一些时间检查问题。我怀疑该事件load不是从image. 但最令人困惑的情况是,当我添加一些代码来仅侦听image'sload事件时,它表明该事件已正确触发......(third snippet)。

然后我决定用$.Deferred( fourth snippet) 写另一个版本。

有效...

你能告诉我有什么问题吗?非常感谢!

4

1 回答 1

1

因为fromEvent(image, 'load')在第一个 sub-observable 上没有完成,其他 sub-observable 一直在等待。所以你应该在第一个事件之后完成 sub-observable。

使用take(1).

摘自您的第二个片段

...
var loadedImageStream = Rx.Observable
                            .fromEvent(image, 'load')
                            .map(function() {                                  
                                return image;
                             })
...

添加 take(1) 以完成 sub-observable

...
var loadedImageStream = Rx.Observable
                            .fromEvent(image, 'load')
                            .map(function() {                                  
                                return image;
                             })
                            .take(1)
...

编辑:

使用concatMap使得加载图像顺序,所以它很慢。

如果你通过了index,你可以使用replace而不是append来保持顺序。在这种情况下,您可以使用flatMap,它可以实现快速并发加载。

$(function () {
    var imageURLList = [
        'https://placehold.it/500x100',
        'https://placehold.it/500x200',
        'https://placehold.it/500x300',
        'https://placehold.it/500x400',
        'https://placehold.it/500x500'
    ];
    var imagesDOM = $('#images');

    Rx.Observable
        .fromArray(imageURLList)
        .do(function (imageURL) {
            imagesDOM.append(new Image()); // placeholder
        })
        .flatMap(function (imageURL, index) {
            var image = new Image();

            var loadedImageStream = Rx.Observable
                .fromEvent(image, 'load')
                .map(function () {
                    return [image, index];
                })
                .take(1)

            image.src = imageURL;

            return loadedImageStream;
        })
        .subscribe(function (image_index) {
            var image = image_index[0];
            var index = image_index[1];

            imagesDOM.children().get(index).replaceWith(image);
        })
})
于 2017-05-25T07:47:10.050 回答