Angular 5中如何直接赋值Observable变量?无需mergeMap与scan
$groups Observable Without mergeMap and scan Hey there! Let's start by breaking down what your original code does: it takes your this.groups array, prepends an empty array, then emits each element with a 1-second delay between them. Finally, scan accumulates these elements into a growing array, so your $groups observable emits a new array every second with all previous items plus the latest one.
If you want to avoid mergeMap and scan and instead have a more "direct assignment" feel, BehaviorSubject is absolutely the right tool here—you just might not have used it the right way to replicate the accumulation behavior. Here's a step-by-step solution:
Solution 1: Use BehaviorSubject with Manual Interval Updates
A BehaviorSubject holds the current value and emits it to new subscribers, which makes it perfect for maintaining your growing array state. You can manually push updates to it on a timer:
// Initialize with an empty array as the initial value private $groups = new BehaviorSubject<any[]>([]); // Function to push groups one by one with 1-second delays private startEmittingGroups(): void { let currentIndex = 0; const emitNext = () => { if (currentIndex >= this.groups.length) return; // Get the current array state, add the next group, and push the new array const currentArray = this.$groups.value; const updatedArray = [...currentArray, this.groups[currentIndex]]; this.$groups.next(updatedArray); currentIndex++; setTimeout(emitNext, 1000); }; emitNext(); } // Call this when you want to start emitting (e.g., in ngOnInit if using Angular) ngOnInit(): void { this.startEmittingGroups(); }
This approach matches your original behavior exactly:
$groupsemits a new array every second- Each new array includes all previous groups plus the latest one
- No
mergeMaporscanneeded—you're directly controlling the state and emissions
Why Your Previous Subject Attempt Might Have Failed
If you tried a regular Subject instead of BehaviorSubject, it doesn't hold a current value—so you couldn't easily access the existing array to append new items. A BehaviorSubject solves this by letting you get the latest emitted value with .value, which is key for building the updated array.
Bonus: Simplified Version (No mergeMap, but still uses scan)
If you're open to keeping scan but ditching mergeMap, you can use delayWhen to handle the timing instead:
this.$groups = from(this.groups) .pipe( delayWhen((_, index) => timer(index * 1000)), scan((acc, curr) => [...acc, curr], []) );
This is more concise, but since you asked to avoid scan, the BehaviorSubject approach is your best bet for that "direct assignment" control you're looking for.
内容的提问来源于stack exchange,提问作者Sudhanshu sharma

