记一次 RXjs 中 Subject 的使用经历

2020-11-03 02:02:02 +08:00
 shakukansp
写项目的时候遇到一个场景
inputA blur 的时候会触发自己的表单验证并发出一个请求,请求数据,填入 input C
点击按钮 B,会触发 A 、C 的表单验证,并发送 A 、C 中的数据给服务端

问题来了,需要保证 A 的异步完成之后再进行 B 的异步请求,于是第一时间想到用 rxjs 的 subject
思路是这样:
创建一个 subject D,
按钮 B 订阅 D,subscribe 的 next 定义为 发送 A 、C 数据给服务端的异步操作
这样 Input A 在异步获取 C 的回调中 触发 subject D 的 next 方法,把请求结果通过 subject 分发给 B
B 再在 subscribe 中接收 D 分发来的值,把数据发送给服务端
但是实操过程 中发现 B 的表单验证会慢于 A 的 next…… 也就是 A 已经请求完数据把数据推送给 D 了,但是 B 表单验证还没完…… 所以接收不到 A 传过来的值,无法继续发送请求

无奈只好又创建了 subject E, 在 A 的请求发出去之前 订阅 B 的表单验证等待其完成,subscribe 的 next 为 A 请求 C 数据的过程……
这样一来,B 就需要在验证完成之后 触发 E 的 next, 把表单验证完成这个事情告诉 A …… A 接到 B 验证成功的消息之后再通过 D 把 请求结果发给 B……

好了,写完之后测试了一下,和预想中的结果一样,完美……
??
那 A blur 的时候如果人没在点击 B,不就没法通知 A 表单验证完成可以继续了吗?
所以需要加一个判断…… 判断 A 的 blur 事件的 relatedTarget 存不存在且是不是 B, 如果不存在或者不是 B 那么就由 A 自己通知自己完成请求 C 的值的过程。

这下终于怎么测都没问题了。

然后我发现直接 click 按钮 B 的时候 也发送 A 的请求,然后在 A 请求的回调里面进行 B 的后续请求即可
只要在 A blur 的时候判断一下 relatedTarget 存不存在且是不是 B
如果不存在或者不是 B 那么 A 就不发请求
完事

蛋疼。
2168 次点击
所在节点    JavaScript
6 条回复
chnwillliu
2020-11-03 05:13:35 +08:00
感觉不需要 Subject 吧。

A blur 会触发验证并发请求,这个就它自己管好自己就 OK 。B click 需要检测当前有无正在 pending 的 A blur 引起的请求,有则等待,无则直接做自己该做的事。

不追求完全函数编程,就可以把 A blur 发请求的 observable 用变量保存起来。

大概这个意思:

```
let pendingRequest = null;

inputABlur$
.pipe(
switchMap(() => {
pendingRequest = httpClient.get('/url', data).pipe(share());
return pendingRequest;
}),
finallize(() => {
pendingRequest = null;
})
)
.subscribe();


buttonBClick$
.pipe(
switchMap(value => {
if (pendingRequest) {
return pendingRequest.pipe(mapTo(value));
}
return of(value);
}),
switchMap(() => httpClient.get('/url-a-c', dataAC))
)
.subscribe();


```
chnwillliu
2020-11-03 05:21:19 +08:00
你这里的表单验证具体是什么操作?不应该是同步的操作么?
xuanbg
2020-11-03 07:41:05 +08:00
在 A 的回调里面显示 B 按钮,这样就能保证 A 返回正确结果后 B 才变得可点击。凡是需要套娃的都可以套用这个方法。
shakukansp
2020-11-03 09:19:04 +08:00
@chnwillliu 一般是用户填完了 a 以后 blur,看到 c 框内的数据改变了,然后再去点 B

但是现在测试的时候有粘贴到 a 以后直接点 B 的情况,这里需要处理 blur -> click 极短时间内的异步流程


@xuanbg 确实,但是这个问题的场景就像上面说的,用户粘贴到 a 以后直接去点了 b,现在想想获取一开始设置 b 不可点击,C 有值的时候再允许点击比较好
chnwillliu
2020-11-03 10:25:09 +08:00
@shakukansp blur 总是会优先于 click 触发的,所以 click 内部判断有无 blur 引起的 request 在 pending 就可以。

不知道你的 A 框中的值不同会不会影响 C 框得到不一样的结果,如果会的话,C 有值再 enable B 按钮这种方案还是有问题。
shakukansp
2020-11-03 10:51:08 +08:00
@chnwillliu 确实不妥,我尝试一下你的方法

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/721202

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX