今天我在使用RxJS时遇到了一个奇怪的问题。请帮我检查一下。
我正在处理的问题是:“给定一系列图像网址,加载并将所有图像附加到div。”
所有要演示的代码片段都在这里:
一开始,我使用the first snippet
。
但是,Rx.Observable.prototype.flatMap
有时会使图像的顺序错误(文档中会注意到这种行为)。所以,我改为使用concatMap
(second snippet
)。
这次只加载第一张图片。我花了一些时间检查问题。我怀疑事件load
未来自image
。但最令人困惑的情况是,当我添加一些代码来监听image
的{{1}}事件时,它会向我显示事件被正确触发......(load
)。
然后我决定使用third snippet
($.Deferred
)编写另一个版本。
有效......
你能告诉我这是什么问题吗?非常感谢你!
答案 0 :(得分:1)
因为第一个子观察者的fromEvent(image, 'load')
没有完成,所以其他子观察者正在等待。所以你应该在第一次事件后完成子观察。
使用take(1)
。
摘自第二段摘录
...
var loadedImageStream = Rx.Observable
.fromEvent(image, 'load')
.map(function() {
return image;
})
...
添加take(1)以完成子可观察
...
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);
})
})