typescript - 为什么 takeWhile 运算符在包含时不过滤?
问题描述
我正在尝试使用将包含选项设置为 true 的 takewhile 运算符,但我正面临一种我不理解的行为。我已经能够隔离一小段代码,我可以在其中重现这里的行为
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
});
解释:如果没有包含标志,它会记录 'value$ = 1' 并且流完成
但是,将 inclusive 标志设置为 true,它会出现 stackoverflow 异常
我的问题是,为什么它不止一次通过 takeWhile 而不是在第一次出现后停止?
这是板凳的链接是否有助于理解: 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);
});
实际操作符的问题在于,在同步调度程序上下文中,当匹配发生时,它会触发另一个迭代并且永远不会达到“完成”。正确的实现是标记匹配并执行另一个最后一次迭代,在该迭代中完成检测标记。
链接到更新的 stackblitz:https ://stackblitz.com/edit/rxjs-ag4aqx
推荐阅读
- textselection - 在 iPad 上禁用 React Native Webview 文本选择放大镜
- linux - Heroku 上的 Docker 超出内存配额
- c# - JUMP 动画不会停止 unity2D
- python-3.x - 如何在 Cloud Composer 中导入自定义模块
- python - 如何通过函数调用在 python django 模板中设置变量?
- vue.js - 试图让 Vue-heatmapjs 在 nuxt 应用程序上工作
- reactjs - MUI v5 disableBackdropClick 在 createTheme 等效项
- android - Android Retrofit2:在没有 GSON 或 JSONObject 的情况下序列化 null
- swift - 使用 UITableViewDropCoordinator 通过具有可区分数据源的 dropDelegate 动画滴
- maven - IntelliJ IDEA 中的 Maven StackOverflowError