轮询史诗行为

时间:2019-05-15 00:05:24

标签: javascript rxjs redux-observable

我正在编写一个史诗,该史诗每隔一定的秒数轮询一次服务器,在这种情况下为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)
.
.
.

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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()))