Асинхронный сеттер/геттер в JavaScript

Я работаю с Web Bluetooth, который требует много асинхронных операций. Я реализовал сеттеры и геттеры для таких свойств, как имя устройства. Асинхронные сеттеры и геттеры по умолчанию не поддерживаются в ES6, поэтому я использовал следующий обходной путь, как было рекомендовано: здесь:

get name() {
  return ( async () => {
    try {
      const data = await this._readData(this.nameCharacteristic);
      const decoder = new TextDecoder("utf-8");
      const name = decoder.decode(data);
      return name;
    } 
    catch (error) {
      return error;
    }
  })();
}

А также:

set name(name) {
  return ( async (name) => {
    const byteArray = new Uint8Array(name.length);
    for (let i = 0; i < name.length; i += 1) {
      byteArray[i] = name.charCodeAt(i);
    }
    return await this._writeData(this.nameCharacteristic, byteArray);
  })(name);
}

Я могу успешно сделать следующее с геттером:

await device.connect();
await device.name;
await device.<some async BLE operation>

Но следующее с установщиком приводит к справочной ошибке «Uncaught ReferenceError: Invalid left-hand side in присваивание» для установщика:

await device.connect();
await device.name = "newName";
await device.<some async BLE operation>

Если я удалю ключевое слово await, ошибка будет исправлена, но сценарий завершится ошибкой, потому что он попытается выполнить две операции GATT одновременно, что не поддерживается.

Так что кажется, что я могу ждать только геттера, а не сеттера. Что-то не так с моей реализацией геттера, что вызывает это? Должен ли я вернуться к использованию такой функции, как device.nameSet(), вместо сеттера при выполнении асинхронных операций?

Для справки, _writeData() и _readData() выглядят так:

async _writeData(characteristic, dataArray) {
  if (!this.bleIsBusy) {
    try {
      this.bleIsBusy = true;
      await characteristic.writeValue(dataArray);
      this.bleIsBusy = false;
    }
    catch (error) {
      return error;
    }
    return Promise.resolve();
  }
  else {
    return Promise.reject(new Error("GATT operation already pending"));
  }
}

async _readData(characteristic) {
  if (!this.bleIsBusy) {
    try {
      this.bleIsBusy = true;
      const dataArray = await characteristic.readValue();
      this.bleIsBusy = false;

      return dataArray;
    }
    catch (error) {
      return error;
    }
  }
  else {
    return Promise.reject(new Error("GATT operation already pending"));
  }
}

person jtg    schedule 21.12.2017    source источник
comment
На мой взгляд, асинхронные геттеры и сеттеры кажутся плохой идеей в качестве стиля кода. Поскольку чтение/запись BLE являются операциями, вместо них следует использовать методы.   -  person Emil    schedule 21.12.2017
comment
Да, я вижу этот момент. В этом проекте он начался с методов с постфиксами -get/-set для получения и установки свойств устройства BLE, но был изменен на шаблон getter/setter, так как он считался более правильным шаблоном для свойств. Теперь я склоняюсь к тому, чтобы вернуться к методам, поскольку асинхронные свойства на самом деле не имеют значения. Возможно, было бы неправильно рассматривать свойства устройства BLE как свойства в контексте JS.   -  person jtg    schedule 21.12.2017


Ответы (1)


Возможно, попробуйте установить значение, возвращаемое из await this._writeData(this.nameCharacteristic, byteArray);...

set name(name) {
  return ( async (name) => {
    const byteArray = new Uint8Array(name.length);
    for (let i = 0; i < name.length; i += 1) {
      byteArray[i] = name.charCodeAt(i);
    }
    const result = await this._writeData(this.nameCharacteristic, byteArray);
    return result;
  })(name);
}
person Grant    schedule 21.12.2017
comment
Спасибо за отзыв, Грант. К сожалению, этот подход приводит к той же ошибке. Кажется, что сеттеры просто нельзя использовать с ключевым словом await, а геттеры могут. - person jtg; 21.12.2017
comment
@jtg Облом! Но полезно знать - person Grant; 22.12.2017