ddu*_*ney 5 javascript asynchronous stream web-serial-api
我有一个 Web 串行端口,我想从中读取一些数据。我想通过使用s 来转换数据TransformStream来进行一些处理(例如将字节解码为字符串、分离出逻辑消息等) 。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"
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我用来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"
}
Run Code Online (Sandbox Code Playgroud)
我在这里做错了什么?释放锁真的TransformStream不会传播到上游吗?我是否必须跟踪管道中每个变压器的实例,以便确保将它们全部解锁?
流规范规定,管道在管道操作期间锁定可读和可写流。
管道锁定可读和可写流,防止它们在管道操作期间被操纵。这允许实现执行重要的优化,例如直接将数据从底层源传输到底层接收器,同时绕过许多中间队列。
是否有其他方法可以表明“管道操作”已完成?
如https://web.dev/serial/#close-port中所述,如果串行端口和成员被解锁,port.close()则关闭串行端口,这意味着已为各自的读取器和写入器调用。readablewritablereleaseLock()
不过,使用转换流时关闭串行端口有点复杂。打电话reader.cancel(),然后打电话writer.close()和port.close()。这会将错误通过转换流传播到底层串行端口。由于错误传播不会立即发生,因此您需要使用之前创建的readableStreamClosed和writableStreamClosed承诺来检测port.readable和何时port.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);
}
Run Code Online (Sandbox Code Playgroud)
// 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();
Run Code Online (Sandbox Code Playgroud)