我试图使用takewhile运算符,并将inclusive选项设置为true,而我正面临一个我不理解的行为。
我已经能够分离出一小段代码,在其中我可以复制这里的行为
import { from, BehaviorSubject } from 'rxjs';
import { map, takeWhile } from 'rxjs/operators';
const value$ = new BehaviorSubject<number>(1);
const source = value$.pipe(
map(x => `value\$ = ${x}`),
takeWhile(x => !x.includes('4'), /*inclusive flag: */true)
);
source.subscribe(x => {
console.log(x);
value$.next(4); // Strange behavior only in this case
});
说明:
如果没有inclusive标志,它将记录“value$=1”,流将完成
但是,当inclusive标志设置为true时,它会出现stackoverflow异常
我的问题是,为什么它要经历一次又一次而不是在第一次发生后停止?
这里有一个板凳的链接,它是否有助于理解:
https://stackblitz.com/edit/rxjs-ag4aqx
最佳答案
在深入研究了一下操作符(https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/takeWhile.ts)的源代码之后,我将向github报告一个问题。
同时,这里有一个固定的自定义TakewhileInclusive运算符
import { from, BehaviorSubject, Observable } from 'rxjs';
import { map, takeWhile } from 'rxjs/operators';
/** Custom takewhile inclusive Custom takewhile inclusive properly implemented */
const customTakeWhileInclusive = <T>(predicate: (value: T) => boolean) => (source: Observable<T>) => new Observable<T>(observer => {
let lastMatch: T | undefined // fix
return source.subscribe({
next: e => {
if (lastMatch) {
observer.complete();
}
else {
if (predicate(e)) {
/*
* Code from https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/takeWhile.ts
*
* if (this.inclusive) {
* destination.next(value); // NO! with a synchronous scheduler, it will trigger another iteration without reaching the next "complete" statement
* and there is no way to detect if a match already occured!
* }
* destination.complete();
*/
// Fix:
lastMatch = e; // prevents from having stackoverflow issue here
}
observer.next(e);
}
},
error: (e) => observer.error(e),
complete: () => observer.complete()
});
});
const value$ = new BehaviorSubject<number>(1);
const source = value$.pipe(
map(x => `value\$ = ${x}`),
//takeWhile(x => !x.includes('4'), true)
customTakeWhileInclusive(x => x.includes('4')) // fix
);
source.subscribe(x => {
console.log(x);
value$.next(4);
});
实际运算符的问题是,在同步调度程序上下文中,当匹配发生时,它会触发另一个迭代,并且永远不会达到“complete”。
正确的实现是标记匹配并执行另一个最后的迭代,在这个迭代中,您将完成对标记的检测。
链接到更新的stackblitz:https://stackblitz.com/edit/rxjs-ag4aqx
关于typescript - 为什么takeWhile运算符不包含时进行过滤?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58064760/