记一次 RXjs 中 Subject 的使用经历 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
shakukansp
V2EX    Javascript

记一次 RXjs 中 Subject 的使用经历

  •  
  •   shakukansp 2020-11-03 02:02:02 +08:00 2675 次点击
    这是一个创建于 1879 天前的主题,其中的信息可能已经有所发展或是发生改变。
    写项目的时候遇到一个场景
    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 就不发请求
    完事

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

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


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

    不知道你的 A 框中的值不同会不会影响 C 框得到不一样的结果,如果会的话,C 有值再 enable B 按钮这种方案还是有问题。
    shakukansp
        6
    shakukansp  
    OP
       2020-11-03 10:51:08 +08:00
    @chnwillliu 确实不妥,我尝试一下你的方法
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4225 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 43ms UTC 01:03 PVG 09:03 LAX 17:03 JFK 20:03
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86