0

我有一个 Web 串行端口,我想从中读取一些数据。我想使用TransformStreams 来做一些处理(例如将字节解码为字符串,分离出逻辑消息等),通过使用pipeThrough来转换数据。但是,一旦我这样做了,我就不能再通过调用reader.releaseLock(). 我在这里做错了什么?

这段代码按我的预期工作(在安全上下文中在浏览器中运行而没有依赖项):

async serialTestWorking() {
  const port = await navigator.serial.requestPort();

  await port.open({baudRate: 9600});
  console.log("Is locked after open?", port.readable.locked);
  // Prints "Is locked after open? false"

  let reader = port.readable.getReader();
  console.log("Is locked after getReader?", port.readable.locked);
  // Prints "Is locked after getReader? true"

  reader.releaseLock();
  console.log("Is locked after releaseLock?", port.readable.locked);
  // Prints "Is locked after releaseLock? false"

  await port.close();
  console.log("Port closed");
  // Prints "Port closed"
}

但是,如果我pipeThrough过去通过 do-nothing 发送输出TransformStream,一切都会崩溃。锁没有被释放,releaseLock最终close无法工作。

async serialTestBroken() {
  const port = await navigator.serial.requestPort();

  await port.open({baudRate: 9600});
  console.log("Is locked after open?", port.readable.locked);
  // Prints "Is locked after open? false"

  let reader = port.readable.pipeThrough(new TransformStream()).getReader();
  console.log("Is locked after getReader?", port.readable.locked);
  // Prints "Is locked after getReader? true"

  reader.releaseLock();
  console.log("Is locked after releaseLock?", port.readable.locked);
  // Prints "Is locked after releaseLock? true"

  await port.close();
  console.log("Port closed");
  // Doesn't make it to the log line
  //throws "TypeError: Failed to execute 'close' on 'SerialPort': Cannot cancel a locked stream"
}

我在这里做错了什么?释放锁TransformStream真的不会向上游传播吗?我是否必须跟踪管道中每个变压器的实例,以便确保将它们全部解锁?

规范说,管道在管道操作期间锁定可读和可写流。

管道锁定可读和可写流,防止它们在管道操作期间被操纵。这允许实现执行重要的优化,例如直接将数据从底层源传输到底层接收器,同时绕过许多中间队列。

是否有其他方式我必须表明“管道操作”已完成?

4

1 回答 1

1

https://web.dev/serial/#close-port中所述,如果串行端口和成员已解锁,port.close()则关闭串行端口,这意味着它们各自的读取器和写入器已调用。readablewritablereleaseLock()

但是,在使用转换流时,关闭串行端口会稍微复杂一些。呼叫reader.cancel(),然后呼叫writer.close()port.close()。这会将错误通过转换流传播到底层串行端口。因为错误传播不会立即发生,所以您需要使用之前创建的readableStreamClosedwritableStreamClosed承诺来检测何时port.readableport.writable已被解锁。取消阅读器会导致流中止;这就是为什么您必须捕获并忽略由此产生的错误。

const textDecoder = new TextDecoderStream();
const readableStreamClosed = port.readable.pipeTo(textDecoder.writable);
const reader = textDecoder.readable.getReader();

// Listen to data coming from the serial device.
while (true) {
  const { value, done } = await reader.read();
  if (done) {
    reader.releaseLock();
    break;
  }
  // value is a string.
  console.log(value);
}
// Later...

const textEncoder = new TextEncoderStream();
const writer = textEncoder.writable.getWriter();
const writableStreamClosed = textEncoder.readable.pipeTo(port.writable);

reader.cancel();
await readableStreamClosed.catch(() => { /* Ignore the error */ });

writer.close();
await writableStreamClosed;

await port.close();
于 2022-02-25T08:35:32.937 回答