nodejs child_process:实时写入stdout&按顺序运行

时间:2018-05-27 14:31:24

标签: javascript node.js child-process

信息
node:v9.4.0

我想按顺序运行外部命令,但要实时查看stdout。

我在下面写了一个例子。这是为了获取./test/中的所有测试用例,然后逐个运行。在此示例中,stdout是实时写入的,但所有测试用例都是同时运行,这是一个问题。

const spawn = require('child_process').spawn;
const fs = require('fs');
let test;

fs.readdirSync('./test/').forEach(file => {
    test = spawn('npm', ['test', 'test/' + file]);

    test.stdout.on('data', (data) => {
        console.log(`${data}`);
    }); 

    test.stderr.on('data', (data) => {
        console.log(`${data}`);
    }); 

    test.on('close', (code) => {
        console.log(`code: ${code}`);
    }); 
});

你能告诉我如何同时实现这两件事吗? - 逐个运行所有测试用例 - 实时编写标准输出

(有人可能会想到为什么我必须逐个运行测试。这是因为那些测试用例要求我使用远程服务器,它不能很好地处理并行任务。服务器不受我的控制,所以我正在尝试在节点js脚本中管理它。)

1 个答案:

答案 0 :(得分:1)

你可以使用JS中的promises来模拟互斥锁(用于异步操作),并在生成每个进程之前锁定并在进程结束时解锁:

class Mutex {
  constructor() {
    this._queue = [];
  }

  lock() {
    return new Promise((resolve, reject) => {
      const allow = () => {
        resolve(this._unlock.bind(this));
      };
      this._queue.push(allow);
      if (this._queue.length === 1) {
        allow();
      }
    });
  }

  _unlock() {
    this._queue.shift();
    const next = this._queue[0];
    if (typeof next === 'function') {
      next();
    }
  }
}

然后您的代码变为:

const spawn = require('child_process').spawn;
const fs = require('fs');
let test;

const mutex = new Mutex();

fs.readdirSync('./test/').forEach(async file => {
    const unlock = await mutex.lock();

    test = spawn('npm', ['test', 'test/' + file]);

    test.stdout.on('data', (data) => {
        console.log(`${data}`);
    }); 

    test.stderr.on('data', (data) => {
        console.log(`${data}`);
    }); 

    test.on('close', (code) => {
        unlock();
        console.log(`code: ${code}`);
    }); 
});