问题描述
本来想用RxJS来优雅的解决这个问题,但是尝试了各种方法后,还是不知道怎么做...
I thought of using RxJS to solve elegantly this problem, but after trying various approaches, I couldn't find out how to do it...
我的需求很普遍:我做了一个 Rest 调用,即.我有一个承诺.如果响应很快,我只想使用结果.如果它来得很慢,我想显示一个微调器,直到请求完成.这是为了避免微调器的闪光,然后是数据.
My need is quite common: I do a Rest call, ie. I have a Promise.If the response comes quickly, I just want to use the result.If it is slow to come, I want to display a spinner, until the request completes.This is to avoid a flash of a the spinner, then the data.
也许可以通过制作两个 observable 来完成:一个带有承诺,另一个带有超时并将微调器显示为副作用.我尝试了 switch()
没有成功,也许是因为另一个 observable 没有产生值.
Maybe it can be done by making two observables: one with the promise, the other with a timeout and showing the spinner as side effect.I tried switch()
without much success, perhaps because the other observable doesn't produce a value.
有人实现过类似的东西吗?
Has somebody implemented something like that?
推荐答案
基于@PhiLho 的 answer,我写了一个管道操作符,它正是这样做的:
Based on @PhiLho's answer, I wrote a pipeable operator, which does exactly that:
export function executeDelayed<T>(
fn : () => void,
delay : number,
thisArg? : any
) : OperatorFunction<T, T> {
return function executeDelayedOperation(source : Observable<T>) : Observable<T> {
let timerSub = timer(delay).subscribe(() => fn());
return source.pipe(
tap(
() => {
timerSub.unsubscribe();
timerSub = timer(delay).subscribe(() => fn());
},
undefined,
() => {
timerSub.unsubscribe();
}
)
);
}
}
基本上它返回一个函数,该函数获取Observable
source
.
然后它使用给定的 delay
启动一个 timer
.
如果此计时器发出 next
事件,则调用该函数.
但是,如果源发出 next
,则 timer
将被取消,并启动一个新的计时器.
在源码的complete
中,最后取消了timer
.然后可以像这样使用此运算符:
Basically it returns a function, which gets the Observable
source
.
Then it starts a timer
, using the given delay
.
If this timer emits a next
-event, the function is called.
However, if the source emits a next
, the timer
is cancelled and a new one is startet.
In the complete
of the source, the timer
is finally cancelled.This operator can then be used like this:
this.loadResults().pipe(
executeDelayed(
() => this.startLoading(),
500
)
).subscribe(results => this.showResult())
我自己没有编写很多操作符,所以这个操作符实现可能不是最好的,但它有效.
欢迎任何有关如何优化它的建议:)
I did not wirte many operators myself, so this operator-implementation might not be the best, but it works.
Any suggestions on how to optimize it are welcome :)
正如@DauleDK 提到的,在这种情况下,错误不会停止计时器,并且 fn
将在 delay
之后被调用.如果这不是你想要的,你需要在 tap
中添加一个 onError
-回调,它调用 timerSub.unsubscribe()
:>
As @DauleDK mentioned, a error won't stop the timer in this case and the fn
will be called after delay
. If thats not what you want, you need to add an onError
-callback in the tap
, which calls timerSub.unsubscribe()
:
export function executeDelayed<T>(
fn : () => void,
delay : number,
thisArg? : any
) : OperatorFunction<T, T> {
return function executeDelayedOperation(source : Observable<T>) : Observable<T> {
let timerSub = timer(delay).subscribe(() => fn());
return source.pipe(
tap(
() => {
timerSub.unsubscribe();
timerSub = timer(delay).subscribe(() => fn());
},
() => timerSub.unsubscribe(), // unsubscribe on error
() => timerSub.unsubscribe()
)
);
}
}
这篇关于RxJS:如果请求很慢则显示加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!