在NodeJS中承诺混乱

时间:2019-02-24 14:39:00

标签: node.js javascript

我很难解决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.*

仅记录的最后一行是正确的。我在围绕这种非阻塞代码执行的问题上束手无策。如果我走错路了,我也愿意接受其他方法。

3 个答案:

答案 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);
  })
}