书接上文,我们知道只要打开定时器,控制台就会一直输出内容。现在我们提出个小需求,只有在文本框输入的内容和定时器的值相等时才输出。用 map 操作符当然可以实现,但最佳实践是使用 filter 操作符。
filter:输入参数为一个条件函数,也就是返回布尔值的函数。意思是对原数据流中的数据进行判断,符合条件的才传递给下面的操作符。
那我们的需求很容易就可以完成了:
combineLatest(
timer$,
input$,
(timeValue, inputValue) => ({count: timeValue, input: inputValue})
)
.pipe(
filter(data => data.count === parseInt(data.input)),
tap(console.log)
).subscribe()
比如我们在输入框输入 3 ,再打开定时器,控制台没有任何输出;当定时器到达 3 时,控制台才会输出。
我们知道当一个流完成时会触发 complete 事件,然而 filter 操作符并不会触发上游数据流的 complete 事件,它只是个阀门,满足它条件的数据才会放过。如果想满足条件后出发上游数据流的 complete 事件,filter 的兄弟 takeWhile 可以帮你完成。
takeWhile:输入参数和 filter 一样, 为一条件函数,返回布尔值,当接收到的数据满足条件函数才会输出,只要不满足就马上触发上游数据流的 complete 事件。
实例最能让你体会到这个操作符的行为。代码很简单,就是把 filter 操作符换成 takeWhile 操作符:
combineLatest(
timer$,
input$,
(timeValue, inputValue) => ({count: timeValue, input: inputValue})
)
.pipe(
takeWhile(data => data.count === parseInt(data.input)),
tap(console.log)
)
.subscribe()
效果图:
一开始是没有输出的,因为 combineLatest 要等两个流都有值才能输出,定时器有初始值 0 , 文本框没有值。当我们在文本框中输入 0 时,控制台输出了,这是因为 combineLatest 产生的对象满足 takeWhile 的条件函数。但当定时器变为 1 时,马上就停止了。这是因为,combineLatest 产生的第二个值不满足 takeWhile 的条件函数,根据定义,马上触发 combineLatest 的 complete 事件,也就是结束数据流,不再有数据产生。
我们在 subscribe 函数中加入完整的回调函数,看下是否真的触发了 complete 事件:
combineLatest(
timer$,
input$,
(timeValue, inputValue) => ({ count: timeValue, input: inputValue })
)
.pipe(
takeWhile(data => data.count === parseInt(data.input)),
tap(console.log)
)
.subscribe(
_ => console.log("next"),
e => console.log("error"),
() => console.log("complete")
)
效果图:
如有任何问题,请添加微信公众号“读一读我”。