【问题标题】:Polling epics behavior投票史诗行为
【发布时间】:2019-05-15 00:05:23
【问题描述】:

我正在编写一个每隔一定秒数轮询服务器的史诗,在这种情况下,3 秒启动延迟,每 5 秒轮询一次,通过管道使用计时器,但我不确定这种行为背后的原因.

我的史诗不是在等待我的内心完成,所以输出真的很奇怪。

我尝试过更改地图并使用exhaustMap,但不确定我是否在正确的树上吠叫。

export const testingEpics = action$ => {
  // Stop upon a end pending action trigger, for debugging/stopping if needed
  const stopPolling$ = action$.pipe(ofType(END_PENDING_ACTIONS));
  return action$.pipe(
    // On begin pending actions
    ofType(BEGIN_PENDING_ACTIONS),
    switchMap(action =>
      // At a 5 second interval
      timer(3 * 1000, 5 * 1000).pipe(
        // Stop when epics see a end pending action
        takeUntil(stopPolling$),
        switchMap(() =>
          // Get the db
          from(getDb()).pipe(
            mergeMap(db => {
              console.log('Run again!!');
              return from(
                new Promise(resolve => setTimeout(resolve, 10000))
              ).pipe(
                // what happens if action is still running but no internet?
                // delay(9.9 * 1000),
                // actions is an array from the db
                // switchmap at top is reason for it, handle for future. lol
                map(actions => console.log('Hello world'))
              );
            })
          )
        )
      )
    )
  );
};

预期的结果将是

(Initial delay 3 seconds) 
Run Again!!
(Wait's 10 seconds for inner promise to complete)
Hello world
(Subsequent delay of 5 seconds)
Run Again!!
(Wait's another 10 seconds for inner promise to complete)
Hello world
(Subsequent delay of 5 seconds)
Run Again!!
(Wait's another 10 seconds for inner promise to complete)
Hello world
(Subsequent delay of 5 seconds)
.
.
.

【问题讨论】:

  • getDb 返回什么?这实际上是调用你的服务器,还是new Promise模拟了对服务器的调用?

标签: javascript rxjs redux-observable


【解决方案1】:

尝试将所有switchMap 更改为concatMap,如果您希望所有请求都通过并排队,exhaustMap 将跳过源 observable 发射,直到内部完成,因此您可能会错过很多请求。另一方面,一旦父 observable 发出,switchMap 将取消内部 observable,因此您的 getDb() 承诺将被取消

【讨论】:

    【解决方案2】:

    intervaltimer 可用于生成一个循环,该循环的执行频率不受实际轮询服务器所需时间的影响。根据您的“预期结果”描述,您似乎希望频率受到实际轮询服务器所需时间长度的影响。我正在考虑您的用例,例如以下(同步)循环:

    delay(3) // synchronously wait 3 seconds
    while (!stopped) {
      pollServer() // synchronously poll server; may take N seconds
      delay(10) // synchronously wait 10 seconds
    }
    

    我会使用repeatWhen 在史诗中构建上述循环。 repeatWhen 使得只有在“循环迭代”完成后才可以轻松启动 10 秒延迟。您只需在可观察的通知中延迟完成事件:

    export const epic = action$ =>
      action$.pipe(
        ofType(BEGIN_PENDING_ACTIONS),
        exhaustMap(action => // ignore actions while the loop is already running
          of(action).pipe( // re-pipe so we can attach `takeUntil` to stop running the loop
            delay(3000), // this is the initial delay
            mergeMap(() =>
              from(getDb()).pipe( // this is the start of the loop iteration
                mergeMap(db => ...), // this is where you poll the server and emit Redux actions
                repeatWhen(complete$ =>
                  complete$.pipe(
                    delay(10000), // on complete, wait 10 seconds, then repeat!
                  )
                ),
              )
            ),
            takeUntil(action$.pipe( // stop on end
              ofType(END_PENDING_ACTIONS)
            )),
          )
        ),
      )
    

    请注意,在上面的示例中,repeatWhen 将简单地重新订阅from(getDb())db 的值将始终是第一次迭代的缓存值。如果您需要在每次迭代时重新执行getDb(),则替换为defer(() => from(getDb()))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-02
      • 1970-01-01
      • 1970-01-01
      • 2019-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多