Как написать асинхронную функцию, которая разрешается при срабатывании генератора событий `data` - PullRequest
0 голосов
/ 12 ноября 2018

Я использую node-serialport для связи с частью оборудования. Он просто пишет команду и получает ответ.

https://serialport.io/docs/en/api-parsers-overview

Работает следующий код:

const port = new SerialPort(path);
const parser = port.pipe(new Readline({ delimiter: '\r', encoding: 'ascii' }));

const requestArray = [];

parser.on('data', (data) => {
  // get first item in array
  const request = requestArray[0];

  // remove first item
  requestArray.shift();

  // resolve promise
  request.promise.resolve(data);
});

export const getFirmwareVersion = async () => {
  let resolvePromise;
  let rejectPromise;

  const promise = new Promise((resolve, reject) => {
    resolvePromise = resolve;
    rejectPromise = reject;
  });

  const title = 'getFirmwareVersion';
  const cmd = 'V\r';

  requestArray.push({
    title,
    cmd,
    promise: {
      resolve: resolvePromise,
      reject: rejectPromise
    }
  });

  await v2Port.write(cmd);

  return promise;
};

Затем из моего приложения (написанного на электронном / реагирующем) я могу вызвать функцию:

<Button onClick={() => {
  let data = await _api.getFirmwareVersion();
  console.log('done waiting...');
  console.log(data);
}>
  Click Me
</Button>

Можно ли как-нибудь изменить этот код, чтобы сделать его более лаконичным?

Есть ли способ получить Обещание из функции async, вместо того, чтобы делать новое Обещание?

Есть ли способ подключиться к уже существующему Потоку Трансформации и как-то передать Обещание туда?

Я также новичок в async / await и хотел бы избежать использования обратных вызовов, особенно в части React / Redux.

Я стремлюсь иметь много этих конечных точек для API (т.е. getFirmwareVersion, getTemperature и т. Д.). Поэтому я хочу сделать код максимально лаконичным. Я не хочу, чтобы пользовательский интерфейс имел какие-либо базовые знания о том, как API получает данные. Просто нужно запросить его, как и любой другой API, и дождаться ответа.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

На основании помощи от Мехмета вот что я закончил:

const _port = new SerialPort(path);
const _parser = _port.pipe(new Readline({ delimiter: '\r', encoding: 'ascii' }));

const waitForData = async () => {
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => reject('Write Timeout'), 500);

    _parser.once('data', (data) => {
      clearTimeout(timeoutId);
      resolve(data);
    });
  });
};

const createAPIFunction = (cmdTemplate, validationString) => {
  return async (config) => {
    try {
      // replace {key} in template with config[key] props
      const cmd = cmdTemplate.replace(/{(\w+)}/g, (_, key) => {
        return config[key];
      });

      _port.write(cmd + '\r');

      const data = await waitForData();

      // validate data
      if (data.startsWith(validationString)) {
        // is valid
        return data;
      } else {
        // invalid data
        throw new Error('Invalid Data Returned');
      }
    } catch (err) {
      throw err;
    }
  };
};

export const getFirmwareVersion = createAPIFunction('V', 'V1');
export const enableSampling = createAPIFunction('G1{scope}', 'G11');
0 голосов
/ 13 ноября 2018

О, я думаю, я понял.Парсер получает данные постоянно.Поэтому, когда приходит запрос, вы ждете следующих данных и отправляете их, когда они поступают.Я предлагаю вам написать промежуточный класс.

Примерно так:

const SerialPort = require('serialport')
const Readline = require('@serialport/parser-readline')
const { EventEmitter } = require('events');

class SerialPortListener extends EventEmitter {
  constructor(path) {
    super();
    this.serialPortPath = path;
  }

  init() {
    this.serialPort = new SerialPort(this.serialPortPath);
    const parser = this.serialPort.pipe(new Readline({ delimiter: '\r', encoding: 'ascii' }));

    parser.on('data', data => this.emit('data', data));
  }
}

Затем вы можете изменить getFirmwareVersion так:

const serialPortListener = new SerialPortListener(path);

serialPortListener.init();

export const getFirmwareVersion = () => {
  return new Promise((resolve, reject) => {
    serialPortListener.once('data', async (data) => {
      try {
        const cmd = 'V\r';
        await v2Port.write(cmd);
        resolve(data);
      } catch (ex) {
        reject(ex);
      }
    });
  });
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...