2016-07-22 48 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