javascript - 延迟除特定项目外的所有项目

标签 javascript rxjs reactive-programming

假设我有一系列 Action 。它们是提示、响应(对提示)或效果。它们以不规则的间隔出现,但假设每个间隔有 1 秒的延迟。

在每个 PROMPT 操作上,我想发出该操作和一个 BEGIN 操作(假设我们想向用户显示消息 N 秒)。所有其他项目都应延迟 N 秒,之后触发 END 操作(隐藏消息)并且一切继续。

这是我的代码(https://rxviz.com/):

const { interval, from, zip, timer } = Rx;
const { concatMap, delayWhen } = RxOperators;

const PROMPT = 'P';
const RESPONSE = 'R';
const EFFECT = 'E';

const BEGIN = '^';
const END = '&';

const convertAction = action => (action === PROMPT) ? [PROMPT, BEGIN, END] : [action];

// Just actions coming at regular intervals
const action$ = zip(
  from([PROMPT, RESPONSE, EFFECT, PROMPT, RESPONSE, EFFECT, EFFECT, EFFECT]),
    interval(1000),
  (a, b) => a,
);

action$.pipe(
  concatMap(action =>
    from(convertAction(action)).pipe(
      delayWhen(action => (action == END) ? timer(5000) : timer(0)),
    ),
  ),
);

我真正想做的是让 PROMPT 之后的第一个 RESPONSE 操作不受延迟的影响。如果它出现在 END Action 之前,它应该立即显示。所以,而不是

P^ &REP^ &REEE

我要收

P^ R &EP^R &EEE

如何在将每个 RESPONSE 放在相应的 PROMPT 之后实现它?假设 PROMPTRESPONSE 之间不会发生任何事件。

最佳答案

如果我理解正确的话,这是一个非常有趣的问题,可以用 Observables 流来解决。这就是我攻击它的方式。

首先,我会将原始逻辑的结果存储在常量 actionDelayed$ 中,即我们在每个 PROMPT 之后引入的流,BEGINEND 操作除以延迟。

const actionDelayed$ = action$.pipe(
  concatMap(action =>
    from(convertAction(action)).pipe(
      delayWhen(action => (action == END) ? timer(5000) : timer(0)),
    ),
  ),
);

然后我将创建 2 个单独的流,response$promptDelayed$,在引入延迟之前仅包含 RESPONSE 操作,并且PROMPT 引入延迟后的 Action ,像这样

const response$ = action$.pipe(
  filter(a => a == RESPONSE)
)
const promptDelayed$ = actionDelayed$.pipe(
  filter(a => a == PROMPT)
)

有了这两个流,我可以创建另一个 RESPONSE Action 流,紧接在 PROMPT 延迟 Action 发出后发出,就像这样

const responseN1AfterPromptN$ = zip(response$, promptDelayed$).pipe(
  map(([r, p]) => r)
)

此时我只需像这样从actionDelayed$ 中删除所有RESPONSE 操作

const actionNoResponseDelayed$ = actionDelayed$.pipe(
  filter(a => a != RESPONSE)
)

并将 actionNoResponseDelayed$responseN1AfterPromptN$ 合并以获得最终流。

完整的代码,用 rxviz 来尝试这是

const { interval, from, zip, timer, merge } = Rx;
const { concatMap, delayWhen, share, filter, map } = RxOperators;

const PROMPT = 'P';
const RESPONSE = 'R';
const EFFECT = 'E';

const BEGIN = '^';
const END = '&';

const convertAction = action => (action === PROMPT) ? [PROMPT, BEGIN, END] : [action];

// Just actions coming at regular intervals
const action$ = zip(
  from([PROMPT, RESPONSE, EFFECT, PROMPT, RESPONSE, EFFECT, EFFECT, EFFECT]),
    interval(1000),
  (a, b) => a,
).pipe(share());

const actionDelayed$ = action$.pipe(
  concatMap(action =>
    from(convertAction(action)).pipe(
      delayWhen(action => (action == END) ? timer(5000) : timer(0)),
    ),
  ),
  share()
);

const response$ = action$.pipe(
  filter(a => a == RESPONSE)
)
const promptDelayed$ = actionDelayed$.pipe(
  filter(a => a == PROMPT)
)
const responseN1AfterPromptN$ = zip(response$, promptDelayed$).pipe(
  map(([r, p]) => r)
)
const actionNoResponseDelayed$ = actionDelayed$.pipe(
  filter(a => a != RESPONSE)
)

merge(actionNoResponseDelayed$, responseN1AfterPromptN$)

在创建 action$actionDelayed$ 流时使用 share 运算符可以避免在创建后续流时重复订阅这些流解决方案中使用的流。

关于javascript - 延迟除特定项目外的所有项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64360113/

相关文章:

javascript - WEBGL-FBO : Why is the DEPTH_COMPONENT texture blank after rendercall

javascript - 使用事件发射器时无法运行我的 Angular 2 应用程序

javascript - 在其派生链中调用 Observable 的 onNext() 方法

javascript - Javascript 中的 react 性与事件?

javascript - 使用 xPath 从 Jquery data-bvalidator 获取输入

javascript - 从文件加载脚本的最佳方法是什么?

javascript - WOW.js : MutationObserver is not supported by your browser

javascript - http toPromise 返回一个对象

angular - 如何在rxjs中实现函数调用的队列?

javascript - Meteor - 从子助手访问父模板变量