#javascript #google-chrome #serial-port #webapi
#javascript #google-chrome #последовательный порт #webapi
Вопрос:
Этот вопрос связан с ситуацией, возникшей при использовании последовательного API Chrome, но, вероятно, может иметь отношение к любому ReadableStream. Я изучил документацию и, вероятно, пропустил какую-то функцию или шаблон.
В браузере Chrome запущена простая программа, получающая доступ к CW keyer (на основе Arduino, но это не важно).
Приложение отправляет команду ключу и ожидает два двоичных байта или строку в качестве ответа (конкретный формат зависит от отправленной команды и не имеет значения).
В случае, если последовательное устройство (не USB / последовательный адаптер, а Arduino) по какой-либо причине пропускает команду, ответ никогда не отправляется, и expectResponse()
приведенная ниже функция никогда не вернет никаких данных и не выдаст никаких исключений. В результате считыватель остается заблокированным, поэтому 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), но я не нашел решения.
PS в реальном приложении serialPort
это глобальная переменная, но это не имеет значения, не так ли?
Ответ №1:
Я не думаю ReadableStream
, что в него встроены тайм-ауты.
Я бы использовал Promise.race
другое обещание, являющееся вашим таймаутом:
let { value, done } = await Promise.race([
reader.read(),
new Promise((_, reject) => setTimeout(reject, TIMEOUT, new Error("timeout")))
]);
(Вы, вероятно, поместили бы этот new Promise
код в служебную функцию.)
Promise.race
наблюдает за выполнением обещаний, выполняя свое обещание на основе первого расчета, который он видит из обещаний в массиве, который вы ему даете. Итак, если read
обещание выполнено (или отклонено) до отклонения обещания тайм-аута, read
урегулирование определяет урегулирование race
обещания. В противном случае race
обещание выполняется на основе расчета (в данном случае отклонения) обещания тайм-аута.