子重绘被childProcess.spawnSync

时间:2016-07-22 02:08:27

标签: javascript node.js dom synchronization electron

我有一个电子/ node.js应用程序,我遇到了麻烦。具体来说,我需要通过更新DOM中的元素,向用户提供有关同步生成的长循环进度的一些反馈。但是,实际显示的内容在循环期间不会更改。整个循环完成后,元素会使用最终的max索引值进行更新。

function dosomething(index,callback) {
   childProcess.spawnSync('app1',...  //takes 1 second
   childProcess.spawnSync('app2',...  //takes 6 seconds, depends on app1 running 1st
   console.log('working on: ' + index);
   callback(index);
}

function dosomethingelse(index) {
    $('#somediv').html(index);  //update progress bar
    console.log('displaying: ' + $('#somediv').html());
}

for(var i=0; i<max; i++){ //max is usually 10-100, loop takes 1 to 10 minutes
    dosomething(i,dosomethingelse);
}

当我将进度html转储到控制台时,它会以索引作为回调递增:

CONSOLE:
working on: 0
displaying: 0
working on: 1
displaying: 1
working on: 2
displaying: 2
...

另外,我试图通过运行以下代码来强制重绘div:

function dosomethingelse(index) {
    $('#somediv').html(index);  //update progress bar
    console.log($('#somediv').html());
    //REDRAW
    document.getElementById("somediv").innerHTML =num;
    document.getElementById("somediv").style.display = 'none';
    document.getElementById("somediv").offsetHeight;
    document.getElementById("somediv").style.display = 'block';
}

根据我的阅读,使用spawnSync使我的二进制应用程序在nodejs上以阻塞模式运行。这直接针对节点的非阻塞核心,但在我的情况下绝对必要,因为我的命令行调用运行了6秒并占用了近100%的CPU。如果我改为使用标准的异步生成,我最终会同时运行50x 100%的进程,并在几分钟左右的时间内完成。同样,没有向用户提供进度反馈。我不明白为什么我的回调没有完成。如果我切换函数以便首先使用dosomethingelse回调调用dosomething,我仍然无法获得DOM更新。

我尝试过的另外两件事:npm sleep

dosomething(i);
var sleep = require('sleep');
sleep.usleep(100);
dosomethingelse(i);

deasync

var deasync = require('deasync');
deasync(dosomething(i));
dosomethingelse(i);

结果相同。另外,如果我取出长期运行的dosomething函数并将其替换为sleep.sleep(3),我会得到相同的结果。 Node只是从一个阻塞任务转到下一个阻塞任务而不更新UI。

1 个答案:

答案 0 :(得分:1)

您似乎只担心同时运行的异步进程太多。但事实上,你可以控制同时运行的数量。

例如:

function runTask(tasks, index, callback) {
  if (index >= tasks.length) {
    callback();
  }
  tasks[index](() => runTask(tasks, index + 1, callback));
}

function queue(tasks, callback) {
  runTask(tasks, 0, callback);
}

通过这种方式,您可以通过一种简单的方法对异步生成进行排队:

const spawn = require('child_process').spawn;

function customSpawn(command, args) {
  return callback => {
    const child = spawn(command, args);
    child.on('close', callback);
  }
} 

queue([customSpawn('app1', []), customSpawn('app2', [])], dosomethingelse);

我从未测试过任何上述代码,因此无法保证其正确性。

另外,如果你想摆脱所有这些回调,请看看promises和generator。

例如,使用promises,它可能如下所示:

function queue(tasks) {
  let index = 0;
  const runTask = arg => {
    if (index >= tasks.length) {
      return Promise.resolve(arg);
    }
    return new Promise((resolve, reject) => {
      tasks[index++](arg).then(arg => resolve(runTask(arg))).catch(reject);
    });
  };
  return runTask();
}

const spawn = require('child_process').spawn;

function customSpawn(command, args) {
  return () => new Promise((resolve, reject) => {
    const child = spawn(command, args);
    child.on('close', code => {
      if (code === 0) {
        resolve();
      } else {
        reject();
      }
    });
  });
}

queue([customSpawn('app1', []), customSpawn('app2', [])])
  .then(dosomethingelse)
  .catch(err => console.error(err));

Try it!

关于for循环的说明:首先使用customSpawn中所示的闭包构建您想要执行的操作,然后将其传递给queue