我很难解决NodeJS上代码执行的异步特性。我有一个简单的功能,可以在Linux机器上获取ip a
的输出并手动解析IP子网。完成后,我只想console.log()
IP子网。
我了解到NodeJS大多是异步运行的,因此我无法期望在console.log()
变量之前完成逻辑。我了解回调的概念来解决此问题,但是我更喜欢在逻辑循环之外访问变量。我转向Promises,这似乎是一个很好的解决方案,但我认为我缺少了一些东西,而且它们没有按我预期的方式工作。这是我的代码如下:
let subnetString = '';
function getIPLinux() {
return new Promise((resolve) => {
const ipOutput = spawn( 'ip', ['a'] );
ipOutput.stdout.on('data', (data) => {
String(data).split('\n').forEach( (line) => {
if ( line.includes('inet') && line.indexOf('inet6') < 0 && line.indexOf('127.0.0.1') < 0 ) {
const ipSubnet = line.split(' ')[5];
const ipStringArray = ipSubnet.split('.');
subnetString = ipStringArray[0] + '.' + ipStringArray[1] + '.' + ipStringArray[2] + '.*';
console.log('Found subnet at end of if loop: ' + subnetString);
}
})
})
console.log('Found subnet at end of promise: ' + subnetString);
resolve();
})
}
getIPLinux().then( () => {
console.log('Found subnet after then: ' + subnetString);
});
我的输出如下:
Found subnet at end of promise:
Found subnet after then:
Found subnet at end of if loop: 192.168.1.*
仅记录的最后一行是正确的。我在围绕这种非阻塞代码执行的问题上束手无策。如果我走错路了,我也愿意接受其他方法。
答案 0 :(得分:2)
spawn()也是异步的。您正在为stdout使用事件回调,这很好,但是您正在解决位于其下方的promise,而无需等待输入完成。试试
ipOutput.on('close', () => {
console.log('Found subnet at end of promise: ' + subnetString);
resolve(subnetString);
});
信守诺言
https://nodejs.org/api/child_process.html#child_process_event_close
答案 1 :(得分:1)
Promise
回调 .on('data', (data) => { // here })
>
subnetString
写为全局变量,将其传递到Promise
内部< / strong>。像这样resolve(subnetString)
catch
。例如,如果找不到有效的行subnetString
,因此可以使用Array.find
而不是进行forEach
循环。它接受“ validation” 回调并返回该项或null
(如果找不到)const isValidLine = l => l.includes('inet') && !l.includes('inet6') && !l.includes('127.0.0.1');
const extractSubnet = l => {
const ipStringArray = l.split(' ')[5].split('.');
return ipStringArray[0] + '.' + ipStringArray[1] + '.' + ipStringArray[2] + '.*';
}
function getIPLinux() {
return new Promise((resolve, reject) => {
const ipOutput = spawn('ip', ['a']);
ipOutput.stdout.on('data', data => {
const line = data.split('\n').find(isValidLine);
// Resolve or Reject your promise here
if (!line) {
reject('Line not found');
} else {
const subnetString = extractSubnet(line);
resolve(subnetString);
}
});
});
}
getIPLinux().then(subnetString => {
console.log('Found subnet after then: ' + subnetString);
});
答案 2 :(得分:0)
这是一个与this one类似的问题,没有通过诺言正确解决。
resolve
在promise构建中被同步调用,promise早于数据到达就解析。应许应使用数据解决,但不能解决。
考虑到只应处理单个data
,它应该是:
function getIPLinux() {
return new Promise((resolve) => {
const ipOutput = spawn( 'ip', ['a'] );
const handler = (data) => {
String(data).split('\n').forEach((line) => {
if (line.includes('inet') && line.indexOf('inet6') < 0 && line.indexOf('127.0.0.1') < 0) {
const ipSubnet = line.split(' ')[5];
const ipStringArray = ipSubnet.split('.');
const subnetString = ipStringArray[0] + '.' + ipStringArray[1] + '.' + ipStringArray[2] + '.*';
ipOutput.stdout.off('data', handler);
resolve(subnetString);
}
})
})
ipOutput.stdout.on('data', handler);
})
}