【问题标题】:Recursive observable method with delay具有延迟的递归可观察方法
【发布时间】:2019-11-15 15:01:45
【问题描述】:

我正在尝试在 Angular 8 中创建具有延迟的递归服务器连接方法。

我试过了:

public connectToServerSafely(): Observable<boolean> {
  if (this.isConnecting) {
    return this.connectToServerSafely().pipe(delay(5000));
  } else if (this.isConnected) {
    return of(true);
  } else {
    return this.connectToServer();
  }
}

connectToServer 方法返回 Observable 的位置取决于连接成功或失败。

问题是这种延迟方法,我不知道为什么,但在建立连接之前,我面临着近 2000 次 connectToServerSafely() 方法调用。 1 秒后建立连接。

为什么延迟方法并没有真正推迟 connectToServerSafely 方法的递归调用(类似于 setTimeout 方法)?

【问题讨论】:

  • 你在哪里设置isConnectingthis.isConnected
  • delay 运算符延迟从可观察源中发射值。它不会以任何方式阻塞调用代码。
  • 这些参数在 connectToServer() 方法中设置。这个方法的第一行是this.isConnecting = true。当建立连接时,我们设置 this.isConnected = true 和 this.isConnecting = false....

标签: javascript angular rxjs observable


【解决方案1】:

this.connectToServerSafely().pipe(delay(5000))不会停止函数调用自身。 delay 运算符只会延迟 发出的值

这是我的方法:

let isConnecting = true;
let isConnected = false;

timer(2000)
  .subscribe(() => (isConnecting = false, isConnected = true));

function connSafely ()/* : Observable<any> */ {
  console.warn('calling `connSafely`');

  if (isConnecting) {
    return timer(500).pipe(concatMap(() => connSafely()))
  }

  if (isConnected) {
    return of(true);
  }

  return connectToServer();
}

function connectToServer () {
  isConnecting = true;

  return of('connecting');
}

connSafely().subscribe();

console.warn("calling 'connSafely'") 应该被调用 5 次(1 用于 初始函数调用 1 4 因为 2000 / 500 = 4)。

注意:请务必使用higher-order mapping operators(switchMap, concatMap, mergeMap/flatMap, exhaustMap) 之一,以确保所有后续函数调用都会自动订阅/取消订阅。

尝试使用tap(() =&gt; connSafely()),您应该只会在控制台中看到两次消息。

StackBlitz。 (向下滚动直到找到您的示例

【讨论】:

  • 谢谢。您在 StackBlitz 上发送给我的示例,有错误“超出最大调用堆栈大小”:)
  • 对不起!.. 我忘了保存 :D。应该会在几分钟内修复。
  • 由于某种原因,它不会记录任何新保存的代码。我不知道是什么问题。
【解决方案2】:

看起来您在订阅的某个位置设置了 this.isConnectingthis.isConnected 以进行流式传输。如果是这样,代码运行异步并且退出条件不起作用,因为您以同步方式设计它

public connectToServerSafely(): Observable<boolean> {
  if (this.isConnecting) {
    // here function will be called until this.isConnecting change to false
    return this.connectToServerSafely().pipe(delay(5000));
  } else if (this.isConnected) {
    return of(true);
  } else {
    return this.connectToServer();
  }
}

【讨论】:

  • 这可以被调用我想要那个,但是为什么这个调用没有被推迟 5 秒。下一个电话在 5 秒后到来?目前我在 1 秒内有 2000 个电话?
  • @Milos 我认为这是因为this.connectToServerSafely().pipe(delay(5000));首先你会调用 api 然后延迟。这意味着 api 将被调用但结果将被延迟
  • 这可能是个问题,那么如何推迟整个 API 调用呢?
  • 你可以试试这样的timer(5000).pipe(switchMap(() =&gt;this.connectToServerSafely()))。但这不是一个正确的解决方案,因为 5 秒后你会收到一批请求
  • 我尝试过超时,但这不是一个好的解决方案(实际上它根本不起作用),因为超时不能作为可观察的返回......必须适合这类问题跨度>
【解决方案3】:

这个解决方案对我有用:

public connectToServerSafely(): Observable<boolean> {
  if (this.isConnecting) {
    return new Observable((observer) => {
        setTimeout(() => {
          this.connectToServerSafely().subscribe(result => {
            observer.next(result);
            observer.complete();
          });
        }, 500);
      });
  } else if (this.isConnected) {
    return of(true);
  } else {
    return this.connectToServer();
  }
}

【讨论】:

    猜你喜欢
    • 2017-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-23
    • 1970-01-01
    • 2016-11-02
    相关资源
    最近更新 更多