Angular 共相关观测中的误差处理

Angular 共相关观测中的误差处理,angular,error-handling,rxjs,observable,bluetooth-lowenergy,Angular,Error Handling,Rxjs,Observable,Bluetooth Lowenergy,根据backtick的建议进行更新: this.ble.connect(macAddr) .pipe( tap(outer => console.log(`outer observable`)), switchMap(() => this.ble.startNotification(macAddr, ENV.CUSTOM_SERVICE, ENV.VALUE_CHARACTERISTIC)

根据backtick的建议进行更新:

    this.ble.connect(macAddr)
    .pipe(
      tap(outer => console.log(`outer observable`)),
      switchMap(() =>
      this.ble.startNotification(macAddr, 
        ENV.CUSTOM_SERVICE,
        ENV.VALUE_CHARACTERISTIC)
          .pipe(
            tap(inner => console.log(`inner observable`)),
            timeout(3000) // <- no further messages
          )
      ),
      // timeout(3000), // <- errors after 18 seconds
      retry(5)
    )
    .subscribe(
      (data) => console.log(`incoming buffer: ${new Uint8Array(data).join(':')}`),
      (error) => console.log(`outer observable ${error}`)
    );

当外部管道超时时,它会在18秒后到达主订阅的错误块。这将对应于3秒间隔加1的5次重试。这表明它正在重试内部可观察到的,但没有记录管道中的水龙头

09:58:08.426 inner observable
09:58:08.426 incoming buffer: 48:0:138:255:0:0:0:0
09:58:26.516 outer observable handling final TimeoutError: Timeout has occurred
期望的行为是,it在出现可观察到的错误时重试连接,并重新订阅通知特性

注意:异步是存在的,因为我必须使用承诺在初始连接之后和通知订阅之前在设备上设置模式。为简单起见省略

await this.ble.write(macAddress, ENV.CUSTOM_SERVICE,
                        ENV.MODE_CHARACTERISTIC, mode);
我一直在交换retryWhen/switchMap/mergeMap/concatMaps的变体,这是我能找到的最接近工作解决方案

this.ble.connect(macAddress)
    .pipe(
      retry(5),
      switchMap(async (value, index) => {
        console.log(`in higher order mapping ${index}`);

        return this.ble.startNotification(macAddress, 
                                          ENV.CUSTOM_SERVICE,
                                          ENV.VALUE_CHARACTERISTIC);
          .pipe(
            timeout(BLE_NOTIFICATION_TIMEOUT),
          ).subscribe(
            result => 
              console.log(`incoming buffer: ${new Uint8Array(result).join(':')}`),
            error => {
              console.log(`listening for notifications`, error);
              return throwError(error);
            }
          );
      })
    )
    .subscribe(
      data => console.log(`'next' block of outer observable`, data)
    , error => console.log(`outer observable handling final ${error}`)
)

当应用程序连接到BLE设备时,它订阅具有Notify属性的特征。连接或通知可观察对象中都可能发生错误。在第一种情况下,它足够干净,重新建立连接并订阅通知。在后一种情况下,除非连接中断,否则错误不会出现在外部可观察对象上,也不会发生重试。我不确定应该以何种方式组合这两个观察值,但如果其中任何一个出现错误,我希望重试连接,并重新启动通知。

有一些问题不利于您:

首先,对
订阅
(在
开关映射
中)的内部调用是非惯用的,行为会很奇怪

作为一个概念,操作符的存在是为了抽象出
订阅
,作为转换/控制观察值的机制。因此,在操作符的回调中直接订阅可观测值与操作符的概念相反,操作符是接受可观测值并返回新值的函数。在这里,您只需要删除对subscribe的调用—当您对整个构造调用subscribe时,内部观察对象的订阅将自动处理

,放置
重试
操作符意味着重试将仅基于可观察到的连接抛出的错误启动。如果您还想捕获通知错误,则需要将其放置在
开关映射之后

Third,您的
switchMap
回调被声明为
async
,即使在没有
wait
关键字的情况下,它也将回调的返回值封装在一个承诺中。如果回调的返回值已经是可观察的(或),那么这可能不是您想要做的

最后(虽然这可能是在粘贴示例时无意中引入的),但在
switchMap
回调中的
.pipe()
调用前面有一个分号,这将导致语法错误

这可能是您想要的结构

this.ble
.connect(macAddress)
.烟斗(
开关映射(()=>
这是我的错
.开始通知(
macAddress,
环境海关服务,
环境价值特性
)
.pipe(超时(BLE_通知_超时))
),
重试(5)//捕获连接失败*或*通知超时
)
.订阅(
(数据)=>console.log(外部可观察数据的“下一个”块),
(error)=>console.log(`outer observable handling final${error}`)
);

感谢您的见解。我已将问题更新到位。我仍然无法让外部可观察对象在内部可观察对象超时时重试连接。看起来内部可观察对象在
超时
切断之前发出一次,这是避免超时条件所需要的全部。如果我理解正确的话,您的期望是计时器在可观察到的通知发送的每个值之后重新启动。这也是可以实现的,只是不需要超时。
timeout
。在我把它正在监听的设备放在一个阻止蓝牙信号的管子里之前,内部可观测设备会发出很多信号:)哦,我明白了,如果你提供一个日期,它就会按照你描述的那样工作。如果它收到一个数字,当两次排放之间的时间间隔较大时,它将超时。BLE_NOTIFICATION_TIMEOUT是一个数字。
this.ble.connect(macAddress)
    .pipe(
      retry(5),
      switchMap(async (value, index) => {
        console.log(`in higher order mapping ${index}`);

        return this.ble.startNotification(macAddress, 
                                          ENV.CUSTOM_SERVICE,
                                          ENV.VALUE_CHARACTERISTIC);
          .pipe(
            timeout(BLE_NOTIFICATION_TIMEOUT),
          ).subscribe(
            result => 
              console.log(`incoming buffer: ${new Uint8Array(result).join(':')}`),
            error => {
              console.log(`listening for notifications`, error);
              return throwError(error);
            }
          );
      })
    )
    .subscribe(
      data => console.log(`'next' block of outer observable`, data)
    , error => console.log(`outer observable handling final ${error}`)
)