如何使用 RxJs 推迟对 AJAX 调用的任何请求,直到前一个请求解决 [英] How can I use RxJs to hold off any requests for an AJAX call until the previous one resolves
问题描述
我有一个 observable,它表示由某个外部组件触发的操作.出于这个问题的目的,我们将其称为 createBananaAction
.我有一个带有方法 create
的 bananaService
执行 AJAX 请求并将创建的香蕉作为 Promise
返回.
I have an observable that represents an action that is triggered by some outside component. For the purpose of this question, let's call it createBananaAction
.
I have a bananaService
with a method create
that performs an AJAX request and returns the created banana as a Promise
.
因此,每当有数据从 createBananaAction
到达时,我们都想调用 bananaService.create()
.
So, whenever some data arrives from the createBananaAction
, we want to call bananaService.create()
.
代码如下:(使用RxJs)
this.createdBananas = createBananaAction.flatMap(() => bananaService.create());
现在,挑战是限制" createBananaAction 以便它只能在收到前一个香蕉后请求另一个香蕉.简单地说:永远不可能有两个同时调用 bananaService.create()
.请注意,我不想及时限制时间,而是在bananaService 执行其操作时忽略所有传入的对新香蕉的请求.
Now, the challenge is to "throttle" the createBananaAction so that it can only request another banana after it received its previous one. Simply put: there can never be two simultaneous calls to bananaService.create()
.
Note that I do not want to throttle in time, but rather ignore all incoming requests for a new banana while the bananaService is doing its thing.
我做了一些研究,发现了看似合适的pausable
运算符.
I did some research and found the seemingly appropriate pausable
operator.
我的代码现在看起来像这样:
My code now looks like this:
const pausableCreateBananaAction = createBananaAction.pausable();
this.createdBananas = pausableCreateBananaAction
.do(() => pausableCreateBananaAction.pause())
.flatMap(() => bananaService.create())
.do(() => pausableCreateBananaAction.resume());
这似乎有效,但我不喜欢我需要这些 do
语句来手动触发 pause
和 resume
声明.
This seems to work, but I don't like the fact that I need these do
statements to manually trigger the pause
and resume
statements.
我发现你可以将一个 observable 传递给 pausable
,然后它应该在适当的时候产生 false
或 true
,但这也需要我手动推送主题中的值.像这样:
I found out you can pass an observable into pausable
which should then produce false
or true
at appropriate times, but this also requires me to manually push values in a subject. Something like this:
const letItGoThrough = new Rx.Subject();
this.createdBananas = createBananaAction
.pausable(letItGoThrough.startWith(true))
.do(() => letItGoThrough.onNext(false))
.flatMap(() => bananaService.create())
.do(() => letItGoThrough.onNext(true));
所以现在我有一个 Rx.Subject(主题就像 RxJs 的训练轮,它是你使用的东西,直到你在 RxJs 有足够的经验,你不再需要它们.)和两个对 do
.
So now I have an Rx.Subject (subjects are like training wheels for RxJs, it's what you use until you become experienced enough at RxJs that you no longer need them.) and two calls to do
.
是否有一种完全反应式"的方式来做我想做的事?或者我是否坚持使用这种外观和感觉对我的口味来说有点过于必要的结构.
Is there a fully "Reactive" way of doing what I want? Or am I stuck with this construct that looks and feels a bit too imperative for my tastes.
先谢谢你.
推荐答案
只需使用 flatMapFirst 而不是 flatMap
:
Just use flatMapFirst instead of flatMap
:
this.createdBananas = createBananaAction.flatMapFirst(() => bananaService.create());
以上假设您的 bananaService.create()
返回一个冷的 observable.如果它返回一个热 observable 或一个 Promise
,那么我们需要用 Observable.defer
包装调用以将其转换为冷 observable,以便 flatMapFirst代码>可以正确控制它的发射:
The above assumes your bananaService.create()
returns a cold observable. If it returns a hot observable or a Promise
, then we need to wrap the call with Observable.defer
to convert it to a cold observable so that flatMapFirst
can control its firing properly:
this.createdBananas = createBananaAction
.flatMapFirst(() => Rx.Observable.defer(() => bananaService.create()));
这篇关于如何使用 RxJs 推迟对 AJAX 调用的任何请求,直到前一个请求解决的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!