2016-07-22 6 views
0

私は問題を抱えているelectron/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 
... 

はまた、私はnoに次のコードを実行することにより、再描画のdivを強制しようとしていますavail:

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がかかるため、私の状況では絶対に必要です。代わりに標準の非同期のスポーンを使用すると、同時に50x100%のプロセスを実行し、同じ時間に数分後に終了します。この場合も、ユーザーに進捗のフィードバックは提供されません。コールバックが完了していない理由を理解できません。私が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を更新せずに、ただ1つのブロックタスクから次のブロックタスクに移動しています。

+0

私はこのようなコマンドラインタスクスプーラを使用することを考えました:http://vicerveza.homeunix.net/~viric/soft/ts/、それを介してすべての私の重いCPUタスクを実行し、毎秒ポーリング進行状況バーを更新します。このアプローチの問題点は、少なくともこのプラットフォームではクロスプラットフォームではないことです。私は、Windowsのポートでより創造的になる必要があります。 – UltrasoundJelly

+0

プロキシキューに非同期とput'emを実行するだけですか? – mash

+0

電子アプリの一部としてユーザーが見るクロム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); 

は、私は上記のコードのいずれかをテストしていないので、決して私はその正しさを保証することはできません。

また、すべてのコールバックを取り除きたい場合は、約束とジェネレータを見てください。

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) )... ' – UltrasoundJelly

+0

@UltrasoundJellyそうでなければ、彼らはすべて同じ時間に再び走ります。 – mash

関連する問題