如何编写在“数据”事件发射器触发时解析的异步函数
How to write an async function that resolves when `data` event emitter fires
我正在使用 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;
};
然后从我的应用程序(用 electron/react 编写)我可以调用函数:
<Button onClick={() => {
let data = await _api.getFirmwareVersion();
console.log('done waiting...');
console.log(data);
}>
Click Me
</Button>
无论如何我可以重构这段代码以使其更简洁吗?
有没有办法从 async
函数中获取 Promise,而不必创建新的 Promise?
有没有办法利用已经存在的转换流并以某种方式将 Promise 传输到那里?
我也是 async/await 的新手,想避免使用回调,尤其是在 React/Redux 方面。
我的目标是为 api(即 getFirmwareVersion
、getTemperature
等)提供很多这样的端点。所以我想让代码尽可能简洁。我不希望 UI 对 API 如何获取数据有任何基础知识。它只需要像其他请求一样请求它 API 并等待响应。
哦,我想我明白了。解析器不断接收数据。所以当一个请求到来时,你等待下一个数据并在它到达时发送它。我建议你写一个中级class.
像这样:
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);
}
});
});
};
在 Mehmet 的帮助下,我得到了以下结果:
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');
我正在使用 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;
};
然后从我的应用程序(用 electron/react 编写)我可以调用函数:
<Button onClick={() => {
let data = await _api.getFirmwareVersion();
console.log('done waiting...');
console.log(data);
}>
Click Me
</Button>
无论如何我可以重构这段代码以使其更简洁吗?
有没有办法从 async
函数中获取 Promise,而不必创建新的 Promise?
有没有办法利用已经存在的转换流并以某种方式将 Promise 传输到那里?
我也是 async/await 的新手,想避免使用回调,尤其是在 React/Redux 方面。
我的目标是为 api(即 getFirmwareVersion
、getTemperature
等)提供很多这样的端点。所以我想让代码尽可能简洁。我不希望 UI 对 API 如何获取数据有任何基础知识。它只需要像其他请求一样请求它 API 并等待响应。
哦,我想我明白了。解析器不断接收数据。所以当一个请求到来时,你等待下一个数据并在它到达时发送它。我建议你写一个中级class.
像这样:
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);
}
});
});
};
在 Mehmet 的帮助下,我得到了以下结果:
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');