RxJS 是一款流行的响应式编程库,它提供了丰富的操作符来方便开发者对流进行处理。在这些操作符中,merge、concat 和 combineLatest 是比较常见的。
在本文中,我们将主要比较 RxJS 中的这三个操作符,从它们的性能表现入手,帮助大家更好地理解它们的特点及适用场景。
merge
RxJS 中的 merge 操作符是用来把多个 Observable 合并为一个的,它会将来自所有 Observable 的数据流打包成一个新的流。merge 操作符不太关心每个 Observable 的顺序,只关心数据流的时间顺序。比如:
const clicks$ = fromEvent(document, 'click'); const interval$ = interval(1000); const merged$ = merge(clicks$, interval$); merged$.subscribe(val => console.log(val));
上面的代码中,我们分别创建了两个 Observable,一个是页面中的点击事件(clicks$),一个是每秒发出一次的 interval(interval$)事件,然后通过 merge 操作符把它们合并得到了一个新的流 merged$。
值得注意的是,merged$ 这个新的流不是按照先后顺序依次发出每个 Observable 内的数据流的,而是把它们合并到一起,按照数据流发出的时间顺序来发出数据。这就是 merge 这个操作符的特点。
concat
concat 操作符是用来连接多个 Observable 的,与 merge 不同的是,concat 操作符会按照顺序连接每个 Observable。比如:
const foo$ = of(1, 2, 3); const bar$ = of(4, 5, 6, 7); const result$ = concat(foo$, bar$); result$.subscribe(val => console.log(val));
上面的代码中,我们分别创建了两个 Observable,分别为 foo$ 和 bar$,然后通过 concat 操作符把它们连接到一起得到了一个新的流 result$。
值得注意的是,concat$ 会先发出 foo$ 的所有数据,再发出 bar$ 的所有数据。如果 foo$ 发出数据时出现 error,则不会继续发出后面的数据流。这也意味着,如果一个 Observable 在执行的过程中一直没有结束,concat$ 操作符就会阻塞后面的 Observable,直到前面的 Observable 发出 complete 事件。
combineLatest
combineLatest 操作符是用来合并多个 Observable 的,它可以把每个 Observable 发出的最新值合并成一个数组,并且在其中任何一个 Observable 发出新值时发出新的数组。比如:
const foo$ = of('a', 'b', 'c'); const bar$ = of(1, 2, 3); const result$ = combineLatest(foo$, bar$); result$.subscribe(val => console.log(val));
上面的代码中,我们分别创建了两个 Observable,分别为 foo$ 和 bar$,然后通过 combineLatest 操作符把它们合并到一起得到了一个新的流 result$。
当一个 Observable 发出新值时,combineLatest 操作符就会把每个 Observable 的最新值重新合并成一个数组,并发出新的数组。
性能比较
merge、concat 和 combineLatest,这三个操作符都可以把多个 Observable 合并成一个新的流。然而,它们之间的性能表现是不一样的。接下来,我们用一组基准测试数据来测试它们之间的性能:
// javascriptcn.com 代码示例 const { performance } = require('perf_hooks'); const { merge, concat, combineLatest, of } = require('rxjs'); const { map } = require('rxjs/operators'); const foo$ = of(0, 1, 2, 3, 4, 5); const bar$ = of(6, 7, 8, 9, 10, 11); const baz$ = of(12, 13, 14, 15, 16, 17); let t1 = performance.now(); merge(foo$, bar$, baz$).pipe(map(val => val * 2)).subscribe(); let t2 = performance.now(); console.log(`merge: ${t2 - t1}ms`); t1 = performance.now(); concat(foo$, bar$, baz$).pipe(map(val => val * 2)).subscribe(); t2 = performance.now(); console.log(`concat: ${t2 - t1}ms`); t1 = performance.now(); combineLatest(foo$, bar$, baz$).pipe(map(val => val[0] * 2 + val[1] * 3 + val[2] * 4)).subscribe(); t2 = performance.now(); console.log(`combineLatest: ${t2 - t1}ms`);
我们分别创建了三个 Observable:foo$,bar$,baz$。每个 Observable 都发出 6 个数据:0-5,6-11,12-17。在测试代码中,我们分别测试了 merge、concat 和 combineLatest 的性能表现,这三个操作符在流订阅前,都会把每个数据流的数据乘以 2 或加权值后再发出。
运行测试代码,我们得到了如下输出:
merge: 0.32102394104003906ms concat: 0.29897093772888184ms combineLatest: 0.28882503509521484ms
从输出可以看出,combineLatest 的性能表现略好于 concat,而 merge 的性能表现相对较差。
操作符比较
综上所述,我们可以对这三个操作符做一个简单总结:
merge 使用场景比较灵活,它适用于不关心顺序的流的合并,但由于它需要一直保持监听流的状态,因此最好在不需要顺序的情况下使用。
concat 更关注每个流的顺序,适用于一个 Observable 执行完成后再执行另外一个 Observable 的场景,注意它会阻塞后面的 Observable 执行,直到前面的 Observable 执行完成。
combineLatest 可以合并多个 Observable 的最新值,并且在其中任何一个 Observable 发出新值时发出新的数组。适用于需要实时更新的场景。
结语
本文主要比较了 RxJS 中的 merge、concat 和 combineLatest 这三个操作符的性能表现,并对它们的适用场景进行了简单说明。
除了这三个操作符之外,RxJS 还提供了大量的操作符,帮助开发者更好地处理数据流,提升软件代码质量。希望本文对读者有所帮助,同时也推荐读者进一步了解 RxJS 功能。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653e0eb47d4982a6eb7a3894