2016-07-22 71 views
0

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

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。如果我使用标准的异步产卵,我最终会同时运行50%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),我会得到相同的结果。节点只是从一个阻塞任务转到下一个,而不更新UI。

+0

我曾考虑过使用像这样的命令行任务假脱机程序:http://vicerveza.homeunix.net/~viric/soft/ts/,通过它运行我所有沉重的CPU任务,然后每秒钟轮询一次更新我的进度条。这种方法的问题在于它不会跨平台(至少有这个假脱机程序)。我将不得不通过Windows端口获得更多创意。 – UltrasoundJelly

+0

只是做异步和put'em在承诺队列? – mash

+0

尝试更新用户视为电子应用程序一部分的Chrome DOM。 – UltrasoundJelly

回答

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); 

我从来没有测试任何上面的代码,因此我不能保证它的正确性。

另外,如果你想摆脱所有这些回调,看一下promise和generator。

例如与承诺它可能是这样的:

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

+0

哇,我不习惯这种方式编码,节点是一个mindf#$%。这需要我在我的项目中实现,看看它是否是bueno。 – UltrasoundJelly

+0

你能否通过构建队列来澄清你的意思?你的意思是设置整个函数调用数组('customSpawn(...)'和'updateprogress(i)'等),它们必须以特定顺序运行,然后将它传递给'queue'?例如:'var myqueue = [“customSpawn('app1',[])”,“customSpawn('app2',[])”,“progress(i)”] ...等等,然后'queue(myqueue )...' – UltrasoundJelly

+0

@超级健康,因为否则,他们都会在同一时间再次运行。 – mash