我的RxJS5管道看起来像这样
Rx.Observable.from([2, 3, 4, 5, 6])
.takeWhile((v) => { v !== 4 })
我希望保留订阅,直到我看到4,但我想最后一个元素4也包括在结果中。所以上面的例子应该是
2, 3, 4
但是,根据official document,takeWhile
运算符不具有包容性。这意味着当遇到与我们提供的谓词不匹配的元素时,它会在没有最后一个元素的情况下立即完成流。结果,上面的代码实际上会输出
2, 3
所以我的问题是,我能够实现takeWhile
的最简单方法是什么?但是也用RxJS发出最后一个元素?
答案 0 :(得分:20)
自RxJS 6.4.0起,现在可以使用takeWhile(predicate, true)
。
已经打开的PR会向 inclusive
添加可选的takeWhile
参数:https://github.com/ReactiveX/rxjs/pull/4115
至少有两种可能的解决方法:
使用concatMap()
:
of('red', 'blue', 'green', 'orange').pipe(
concatMap(color => {
if (color === 'green') {
return of(color, null);
}
return of(color);
}),
takeWhile(color => color),
)
使用multicast()
:
of('red', 'blue', 'green', 'orange').pipe(
multicast(
() => new ReplaySubject(1),
subject => subject.pipe(
takeWhile((c) => c !== 'green'),
concat(subject.take(1),
)
),
)
我一直在使用这个运算符,所以我把它添加到我自己的一组额外的RxJS 5运算符中:https://github.com/martinsik/rxjs-extra#takewhileinclusive
此RxJS 5问题中还讨论了此运算符:https://github.com/ReactiveX/rxjs/issues/2420
2019年1月:更新了RxJS 6
答案 1 :(得分:3)
如果您的比较确切地知道最后一个元素是什么(例如!==
),您可以自己重新添加:
Rx.Observable.from([2, 3, 4, 5, 6])
.takeWhile((v) => v !== 4)
.concat(Rx.Observable.of(4))
.subscribe(console.log)
答案 2 :(得分:2)
我遇到了同样的问题,我需要包含最后一个元素,所以我选择保留对订阅的引用并取消订阅 onNext
回调中的 当条件满足时。使用您的示例代码:
const subscription = Observable.of('red', 'blue', 'green', 'orange')
.subscribe(color => {
// Do something with the value here
if (color === 'green') {
subscription.unsubscribe()
}
})
这对我有用,因为它也导致可观察源停止发射,这是我在我的场景中所需要的。
我意识到我没有使用takeWhile
运算符,但主要目标是实现的,没有任何变通方法或额外的代码。
我不是强迫事情以他们不适合的方式工作的粉丝。
这样做的缺点是:
onCompleted
由于某种原因没有被调用,但我检查了源实际上是停止发射。答案 3 :(得分:2)
您可以使用endWith(value)
(与许多RxJS代码不同)
很好地自我记录。
const example = source.pipe(
takeWhile(val => val != 4),
endWith(4));
PS。另请注意,takeUntil
不带谓词,因此,如果您尝试使用该运算符来解决此问题,则不能。这是完全不同的方法签名。
官方文档: https://rxjs-dev.firebaseapp.com/api/operators/endWith
答案 4 :(得分:1)
UPDATE 2019年3月,rsjx
版本6.4.0
:takeWhile
最后有一个可选的inclusive
参数,该参数允许保留第一个破坏条件的元素。因此,现在的解决方案就是简单地将 true 用作takeWhile
的第二个参数:
import { takeWhile } from 'rxjs/operators';
import { from } from 'rxjs';
const cutOff = 4.5
const example = from([2, 3, 4, 5, 6])
.pipe(takeWhile(v => v < cutOff, true ))
const subscribe = example.subscribe(val =>
console.log('inclusive:', val)
);
输出:
inclusive: 2
inclusive: 3
inclusive: 4
inclusive: 5
住在这里:
https://stackblitz.com/edit/typescript-m7zjkr?embed=1&file=index.ts
请注意,第5个破坏条件的元素。注意,当您遇到诸如endWith
这样的动态条件并且不知道最后一个元素是什么时,v < cutOff
并不是真正的解决方案。
感谢@martin指出此拉取请求的存在。
答案 5 :(得分:0)
就我而言,我无法预测最终值。我也只想要一个涉及普通,简单运算符的解决方案,并且我希望我可以重用一些东西,所以我不能依赖真实的值。我唯一想到的就是这样定义自己的运算符:
import { pipe, from } from 'rxjs';
import { switchMap, takeWhile, filter, map } from 'rxjs/operators';
export function doWhile<T>(shouldContinue: (a: T) => boolean) {
return pipe(
switchMap((data: T) => from([
{ data, continue: true },
{ data, continue: shouldContinue(data), exclude: true }
])),
takeWhile(message => message.continue),
filter(message => !message.exclude),
map(message => message.data)
);
}
有点奇怪,但是它对我有用,我可以导入并使用它。