如何在 "hangs" 时中断 Reader (需要 Reader.read() 超时)

How can I interrupt a Reader when it "hangs" (need a timeout on Reader.read() )

这个问题与使用 Chrome Serial API 时发生的情况有关,但可能与任何 ReadableStream 有关。我研究了文档,可能遗漏了一些功能或模式。

一个简单的程序是运行在Chrome浏览器中访问CW keyer(基于Arduino,但这并不重要)。

应用程序向键控器发送命令并期望两个二进制字节或字符串作为响应(具体格式取决于发送的命令,并不重要)。

如果串行设备(不是 USB/serial 适配器,而是 Arduino)由于任何原因错过了命令,则永远不会发送响应,下面的函数 expectResponse() 永远不会 return 任何数据,也不会抛出任何异常。结果,Reader 保持锁定状态,因此 ReadableStream 无法关闭,因此串口也无法关闭。

此外,根据应用程序结构,如果其他命令成功发送到键控器,则可能无法读取第二个响应,因为第一个 reader 阻塞流,直到它被释放, 无法创建新的 Reader。


async function expectResponse( serialPort ) {
   const reader = serialPort.readable.getReader() ;
   let { value, done } = await reader.read() ; // this never returns because no data arrive, not possible to "break"
}

async function disconnect( serialPort ) {
   // ... some cleanup ...
   // naive attempt to unlock ReadableStream before closing 
   await serialPort.readable.getReader().releaseLock() // this will throw exception - cannot create  new reader while another one is still active and locks the stream
   // ...
   await serialPort.close(); // this will throw exception - cannot close port because readable stream is locked
}

serialPort 是 return 由 navigator.serial.requestPort()

编辑的对象

我确信我一定错过了 API 文档中的重要内容(ReadableStreamReader API,而不是 Serial API ),但我没有找到解决方案。

P.S。在真实的应用程序中 serialPort 是一个全局变量,但没有关系,是吗?

我认为 ReadableStream 没有内置超时。

我会使用 Promise.race,另一个承诺是你的超时:

let { value, done } = await Promise.race([
    reader.read(),
    new Promise((_, reject) => setTimeout(reject, TIMEOUT, new Error("timeout")))
]);

(您可能会将 new Promise 代码放在实用函数中。)

Promise.race 观看 promises 竞赛,根据它在您提供的数组中看到的 promise 的第一个结算来结算它的 promise。因此,如果 read 的承诺在超时承诺被拒绝之前得到履行(或被拒绝),则 read 的结算决定了 race 承诺的结算。否则,race 承诺基于超时承诺的结算(在本例中为拒绝)结算。