0%

rxjs 操作符 concatMap

concatMap

返回一个Observable,该Observable发出基于对源Observable发出的值调用提供的函数,该函数返回所谓的内部Observable。每个新的内部Observable和前一个内部Observable连接在一起。内部的Observable在无限制的缓冲区中聚集,以等待轮流订阅。

注意:内部Observable以串行的方式等待前一个Observable完成再订阅下一个。

应用

有一个图片列表,我们需要图片加载完毕后做一些操作。

首先处理单张图片的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
loadImage(src: string): Observable<HTMLImageElement> {
return Observable.create((observer: Observer<HTMLImageElement>) => {
const image: HTMLImageElement = new Image();
image.src = src;
console.log('src', src);

image.onload = () => {
observer.next(image);
};
image.onerror = (err) => {
console.log('error');
observer.error(err);
};
});
}

定义了一个方法,通过返回一个Observable的方式,当图片加载完成后发出值。

我们有一个图片列表:

1
2
3
4
imageSrcArr: string [] = [
'/assets/image/1.png',
'/assets/image/2.png',
];

首先我们通过fromArray操作符,将源数组转化为Observable源:

1
2
fromArray(this.imageSrcArr).subscribe(image => {
});

然后加上concatMap操作符,将源数组的每个值应用loadImage方法进行转化:

1
2
3
4
5
fromArray(this.imageSrcArr).pipe(
concatMap(src => this.loadImageByRXJS(src))
).subscribe(image => {
console.log('images', image);
});

这样,按理来讲,console里面输出的应该是加载图片后的dom,源数组有几条数据就应该有几个图片。

然而,无论怎么搞,都只出现第一张,这是为啥?

回看我们的图片加载方法,在创建Observable之后只是发射出值,并没有complete。这就是问题所在。

映射后的Observable以串行方式等待订阅,上一个Observable完成之后才会订阅下一个。所以,我们的loadImage需要改写一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
loadImage(src: string): Observable<HTMLImageElement> {
return Observable.create((observer: Observer<HTMLImageElement>) => {
const image: HTMLImageElement = new Image();
image.src = src;
console.log('src', src);

image.onload = () => {
observer.next(image);
observer.complete();
};
image.onerror = (err) => {
console.log('error');
observer.error(err);
};
});
}

图片加载完毕后这个内部的Observable应该要完成,这样才会订阅下一个Observable


智商税啊,对这个操作符不是很明确,昨晚多搞了几个小时,😌