问题描述
这个问题与使用 Chrome Serial API 时发生的情况有关,但可能与任何 ReadableStream 相关。我研究了文档,可能遗漏了一些功能或模式。
Chrome 浏览器中正在运行一个简单的程序,访问 CW 键控器(基于 Arduino,但这并不重要)。
应用程序向键控器发送命令,并需要两个二进制字节或字符串作为响应(具体格式取决于发送的命令,并不重要)。
如果串行设备(不是 USB/串行适配器,而是 Arduino)因任何原因错过命令,则永远不会发送响应,并且下面的函数 expectResponse()
永远不会返回任何数据,也不会抛出任何异常。结果,Reader 保持锁定状态,因此无法关闭 ReadableStream,因此也无法关闭串行端口。
此外,根据应用程序结构,如果其他命令成功发送到键控器,可能无法读取第二个响应,因为第一个读取器阻塞了流,直到它被释放,才能创建新的读取器.
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
是 navigator.serial.requestPort()
我确信我一定遗漏了 API 文档(ReadableStream
或 Reader
API,而不是 Serial
API)中的一些重要内容,但我没有找到解决方案。
附言在实际应用中,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 的竞争,根据它在你给它的数组中看到的 promises 的第一个结算来解决它的 promises。因此,如果 read
的承诺在超时承诺拒绝之前得到履行(或拒绝),则 read
的结算决定了 race
承诺的结算。否则,race
承诺基于超时承诺的解决(在本例中为拒绝)。