Странное поведение Rx.Observable.prototype.fromEvent()
Сегодня я видел странную проблему при использовании RxJS. Пожалуйста, помогите мне проверить это.
Проблема, над которой я работаю: "Учитывая массив URL-адресов изображений, загрузите и добавьте все изображения в div".
Все фрагменты кода для демонстрации здесь:
В начале я использовал the first snippet
,
Тем не мение, Rx.Observable.prototype.flatMap
иногда размещает изображения в неправильном порядке (такое поведение замечено в документации). Итак, я перешел на использование concatMap
(second snippet
).
На этот раз загружается только первое изображение. Я взял некоторое время, чтобы осмотреть проблему. Я сомневаюсь что событие load
не запускается из image
, Но самая запутанная ситуация - когда я добавляю код для прослушивания image
"s load
только событие, оно показало мне, что событие срабатывает правильно... (third snippet
).
Тогда я решил написать другую версию, используя $.Deferred
(fourth snippet
).
Это сработало...
Не могли бы вы сказать мне, в чем проблема? Большое спасибо!
1 ответ
Так как fromEvent(image, 'load')
на первой суб-наблюдаемой не завершена, другие суб-наблюдаемые ждут вечно. Таким образом, вы должны заполнить суб-наблюдаемый после первого события.
использование take(1)
,
выдержка из вашего второго фрагмента
...
var loadedImageStream = Rx.Observable
.fromEvent(image, 'load')
.map(function() {
return image;
})
...
Добавьте дубль (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);
})
})