Rx.Observable.prototype.fromEvent() 的奇怪行为
Strange behavior of Rx.Observable.prototype.fromEvent()
今天我在使用RxJS 时遇到了一个奇怪的问题。请帮我检查一下。
我正在处理的问题是:"Given an array of image URLs, load and append all images to a div."
所有要演示的代码片段都在这里:
一开始我用的是the first snippet
.
但是,Rx.Observable.prototype.flatMap
有时会以错误的顺序放置图像(文档中已注意到此行为)。所以,我改为使用 concatMap
(second snippet
).
这次只加载了第一张图片。我花了一些时间检查问题。我怀疑事件 load
不是从 image
触发的。但最令人困惑的情况是,当我添加一些代码来仅侦听 image
的 load
事件时,它向我显示该事件已正确触发......(third snippet
)。
然后我决定使用$.Deferred
(fourth snippet
)编写另一个版本。
成功了...
你能告诉我问题是什么吗?非常感谢!
因为fromEvent(image, 'load')
第一个子observable没有完成,其他子observable永远在等待。所以你应该在第一个事件后完成 sub-observable。
使用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);
})
})
今天我在使用RxJS 时遇到了一个奇怪的问题。请帮我检查一下。
我正在处理的问题是:"Given an array of image URLs, load and append all images to a div."
所有要演示的代码片段都在这里:
一开始我用的是the first snippet
.
但是,Rx.Observable.prototype.flatMap
有时会以错误的顺序放置图像(文档中已注意到此行为)。所以,我改为使用 concatMap
(second snippet
).
这次只加载了第一张图片。我花了一些时间检查问题。我怀疑事件 load
不是从 image
触发的。但最令人困惑的情况是,当我添加一些代码来仅侦听 image
的 load
事件时,它向我显示该事件已正确触发......(third snippet
)。
然后我决定使用$.Deferred
(fourth snippet
)编写另一个版本。
成功了...
你能告诉我问题是什么吗?非常感谢!
因为fromEvent(image, 'load')
第一个子observable没有完成,其他子observable永远在等待。所以你应该在第一个事件后完成 sub-observable。
使用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);
})
})