DOM 重绘被 childProcess.spawnSync 阻止
DOM redraw being blocked by childProcess.spawnSync
我有一个 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 上处于阻塞模式。这直接针对节点的非阻塞核心,但在我的情况下是绝对必要的,因为我的命令行调用 运行s 持续 6 秒并且占用了近 100% CPU。如果我改为使用标准的异步生成,我最终会同时处理 50x 100% 进程 运行ning,大约在同一时间几分钟后完成。同样,没有向用户提供进度反馈。我不明白为什么我的回调没有完成。如果我切换函数以便首先使用 dosomething
回调调用 dosomethingelse
,我仍然没有得到 DOM 更新。
我尝试过的另外两件事:npm sleep:
dosomething(i);
var sleep = require('sleep');
sleep.usleep(100);
dosomethingelse(i);
和deasync:
var deasync = require('deasync');
deasync(dosomething(i));
dosomethingelse(i);
同样的结果。此外,如果我取出长 运行ning dosomething
函数并将其替换为 sleep.sleep(3)
,我会得到相同的结果。节点只是从一个阻塞任务转到下一个阻塞任务而不更新 UI.
您似乎只担心同时 运行 太多的异步进程。但其实你可以控制同时有多少运行
例如像这样:
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 和生成器。
例如,对于 promise,它可能看起来像这样:
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));
关于 for 循环的注意事项:首先使用闭包构建队列,如 customSpawn
中所示,然后将其传递给 queue
。
我有一个 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 上处于阻塞模式。这直接针对节点的非阻塞核心,但在我的情况下是绝对必要的,因为我的命令行调用 运行s 持续 6 秒并且占用了近 100% CPU。如果我改为使用标准的异步生成,我最终会同时处理 50x 100% 进程 运行ning,大约在同一时间几分钟后完成。同样,没有向用户提供进度反馈。我不明白为什么我的回调没有完成。如果我切换函数以便首先使用 dosomething
回调调用 dosomethingelse
,我仍然没有得到 DOM 更新。
我尝试过的另外两件事:npm sleep:
dosomething(i);
var sleep = require('sleep');
sleep.usleep(100);
dosomethingelse(i);
和deasync:
var deasync = require('deasync');
deasync(dosomething(i));
dosomethingelse(i);
同样的结果。此外,如果我取出长 运行ning dosomething
函数并将其替换为 sleep.sleep(3)
,我会得到相同的结果。节点只是从一个阻塞任务转到下一个阻塞任务而不更新 UI.
您似乎只担心同时 运行 太多的异步进程。但其实你可以控制同时有多少运行
例如像这样:
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 和生成器。
例如,对于 promise,它可能看起来像这样:
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));
关于 for 循环的注意事项:首先使用闭包构建队列,如 customSpawn
中所示,然后将其传递给 queue
。