Major Changes Between RxJS 6 and RxJS 7
1. Import Changes
RxJS 6:
javascript// Creation operators import { of, from, interval } from 'rxjs'; // Operators (using pipe) import { map, filter, switchMap } from 'rxjs/operators'; // Utility functions import { Subscription } from 'rxjs';
RxJS 7:
javascript// Import method is basically the same, but more modular import { of, from, interval } from 'rxjs'; import { map, filter, switchMap } from 'rxjs/operators'; // Added some new operators import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
2. New Operators
RxJS 7 added several useful operators:
1. partition
Splits an Observable into two based on a predicate function.
javascriptimport { of, partition } from 'rxjs'; const source$ = of(1, 2, 3, 4, 5, 6); const [evens$, odds$] = partition(source$, x => x % 2 === 0); evens$.subscribe(x => console.log('Even:', x)); // 2, 4, 6 odds$.subscribe(x => console.log('Odd:', x)); // 1, 3, 5
2. Improved tap
tap now accepts an object to handle different notification types separately.
javascriptimport { of } from 'rxjs'; import { tap } from 'rxjs/operators'; of(1, 2, 3).pipe( tap({ subscribe: () => console.log('Subscribed'), next: value => console.log('Next:', value), error: error => console.log('Error:', error), complete: () => console.log('Completed'), unsubscribe: () => console.log('Unsubscribed') }) ).subscribe();
3. connectable Operator
Simplifies the creation of multicast Observables.
javascriptimport { interval, connectable } from 'rxjs'; import { take } from 'rxjs/operators'; const source$ = interval(1000).pipe(take(5)); const connectable$ = connectable(source$); connectable$.subscribe(value => console.log('Subscriber 1:', value)); connectable$.subscribe(value => console.log('Subscriber 2:', value)); connectable$.connect();
4. Improved shareReplay
shareReplay now supports configuration objects.
javascriptimport { interval } from 'rxjs'; import { shareReplay, take } from 'rxjs/operators'; const shared$ = interval(1000).pipe( take(5), shareReplay({ bufferSize: 2, refCount: true }) );
5. Improved Type Inference for filter
Better TypeScript type inference.
javascriptimport { of } from 'rxjs'; import { filter } from 'rxjs/operators'; const source$ = of(1, 2, 3, 4, 5); // In RxJS 7, type inference is more accurate const even$ = source$.pipe( filter(x => x % 2 === 0) // x is inferred as number ); even$.subscribe(x => console.log(x)); // x is of type number
3. Deprecated Operators
The following operators are deprecated in RxJS 7:
1. throwError
RxJS 6:
javascriptimport { throwError } from 'rxjs'; throwError('Error message');
RxJS 7:
javascriptimport { throwError } from 'rxjs'; // Recommended to use factory function throwError(() => new Error('Error message'));
2. Static Methods concat and merge
Still available, but concatWith and mergeWith are recommended.
javascriptimport { of, concat, merge } from 'rxjs'; // Still available concat(of(1), of(2)).subscribe(); merge(of(1), of(2)).subscribe(); // Recommended of(1).pipe(concatWith(of(2))).subscribe(); of(1).pipe(mergeWith(of(2))).subscribe();
4. Performance Optimizations
1. Smaller Bundle Size
RxJS 7 reduces bundle size through tree-shaking optimization.
javascript// RxJS 7 only imports needed operators import { of } from 'rxjs'; import { map } from 'rxjs/operators'; // Only of and map will be included in the bundle
2. Faster Execution Speed
Execution speed of some operators has been optimized.
javascriptimport { of } from 'rxjs'; import { map, filter } from 'rxjs/operators'; // These operators execute faster in RxJS 7 of(1, 2, 3, 4, 5).pipe( map(x => x * 2), filter(x => x > 5) ).subscribe();
5. TypeScript Improvements
1. Better Type Inference
javascriptimport { of } from 'rxjs'; import { map, filter } from 'rxjs/operators'; // In RxJS 7, type inference is more accurate const result$ = of(1, 2, 3).pipe( map(x => x.toString()), // Inferred as Observable<string> filter(x => x.length > 0) );
2. Strict Type Checking
javascriptimport { of } from 'rxjs'; import { map } from 'rxjs/operators'; // In RxJS 7, type checking is stricter of(1, 2, 3).pipe( map(x => x.toUpperCase()) // TypeScript error: number doesn't have toUpperCase );
6. Error Handling Improvements
1. Better Error Messages
javascriptimport { of } from 'rxjs'; import { map } from 'rxjs/operators'; of(1, 2, 3).pipe( map(x => { if (x === 2) throw new Error('Custom error'); return x; }) ).subscribe({ error: error => { console.log(error.message); // Clearer error message } });
2. Improved onErrorResumeNext
javascriptimport { of, onErrorResumeNext } from 'rxjs'; const source1$ = of(1, 2, 3).pipe( map(x => { if (x === 2) throw new Error('Error'); return x; }) ); const source2$ = of(4, 5, 6); onErrorResumeNext(source1$, source2$).subscribe(console.log); // Output: 1, 4, 5, 6
7. Scheduler Improvements
1. Improved animationFrameScheduler
javascriptimport { interval, animationFrameScheduler } from 'rxjs'; import { take } from 'rxjs/operators'; // In RxJS 7, animationFrameScheduler is more stable interval(0, animationFrameScheduler).pipe( take(60) ).subscribe(frame => { console.log('Frame:', frame); });
2. Improved asapScheduler
javascriptimport { of, asapScheduler } from 'rxjs'; // In RxJS 7, asapScheduler has better performance of(1, 2, 3, asapScheduler).subscribe(value => { console.log(value); });
8. Testing Tool Improvements
1. Improved TestScheduler
javascriptimport { TestScheduler } from 'rxjs/testing'; // In RxJS 7, TestScheduler is easier to use const testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); testScheduler.run(({ cold, expectObservable }) => { const source$ = cold('-a-b-c|'); const expected = '-a-b-c|'; expectObservable(source$).toBe(expected); });
2. Improved marble testing
javascriptimport { TestScheduler } from 'rxjs/testing'; // In RxJS 7, marble testing is more intuitive testScheduler.run(({ cold, hot, expectObservable, expectSubscriptions }) => { const source$ = cold('-a-b-c|'); const expected = '-a-b-c|'; expectObservable(source$).toBe(expected); });
9. Documentation and Example Improvements
1. Better Documentation
RxJS 7 provides more detailed documentation and examples.
javascript// Official documentation provides more practical examples import { of } from 'rxjs'; import { map, filter } from 'rxjs/operators'; of(1, 2, 3, 4, 5).pipe( map(x => x * 2), filter(x => x > 5) ).subscribe(console.log);
2. More Best Practices
Official documentation includes more best practice recommendations.
javascript// Recommended to use pipe instead of chaining import { of } from 'rxjs'; import { map, filter } from 'rxjs/operators'; // ✅ Recommended of(1, 2, 3).pipe( map(x => x * 2), filter(x => x > 5) ).subscribe(); // ❌ Not recommended of(1, 2, 3).pipe( map(x => x * 2) ).pipe( filter(x => x > 5) ).subscribe();
10. Migration Guide
1. Migrating from RxJS 6 to RxJS 7
bash# Upgrade RxJS npm install rxjs@7 # Check for deprecated APIs npm run lint
2. Common Migration Issues
Issue 1: Usage of throwError
javascript// ❌ RxJS 6 throwError('Error message'); // ✅ RxJS 7 throwError(() => new Error('Error message'));
Issue 2: Type inference issues
javascript// May need explicit types import { of } from 'rxjs'; import { map } from 'rxjs/operators'; const result$ = of(1, 2, 3).pipe( map(x => x.toString()) ) as Observable<string>;
Summary
Major improvements of RxJS 7 compared to RxJS 6:
- New Operators:
partition,connectable, etc. - Performance Optimization: Smaller bundle size, faster execution speed
- TypeScript Improvements: Better type inference and strict type checking
- Error Handling: Better error messages and handling mechanisms
- Scheduler Improvements: More stable and efficient schedulers
- Testing Tools: Easier to use TestScheduler
- Documentation Improvements: More detailed documentation and examples
Migrating to RxJS 7 can bring better performance and development experience, but be aware of some API changes.