我想执行一个shell生成脚本,并将当前执行状态发送给angular客户。问题是,调用后不会立即执行发射。程序等待完成全部功能,然后将所有这些发射一起发送。
const express = require('express');
const app = express();
const socketIO = require('socket.io');
const execSync = require('child_process').execSync;
[...]
app.post('/bootupserver', function(req, res) {
progress = [];
io.emit('update', getCurrentServerState());
const filePath = path.join(__dirname, 'bootserver.json');
const file = fs.readFileSync(filePath, { encoding: 'utf-8' });
progress = Object.values(JSON.parse(file));
progress.forEach(line => {
line[0] = 1;
io.emit('update', getCurrentServerState());
execSync(line[2]);
line[0] = 2;
});
io.emit('update', getCurrentServerState());
res.sendStatus(200);
});
[...]
要了解forEach,这里是我的虚拟bootserver.json。一个数组包含三个值:状态(0 =等待,1 = wip,2 =完成),名称和命令。
{
"0": [2, "0", "sleep 2"],
"1": [2, "A", "sleep 1"],
"2": [1, "b", "sleep 0.2"],
"3": [0, "C", "sleep 1"],
"4": [0, "d", "sleep 0.2"],
"5": [0, "E", "sleep 1"],
"6": [0, "f", "sleep 5"],
"7": [0, "G", "sleep 2"],
}
这是我用来收听消息的角度代码:
const observable = new Observable<string>((observer: any) => {
io(url, { secure: true }).on('update', (msg: string) => {
observer.next(msg);
});
});
我希望有一种冲洗/强制发射直接更新前端的机制。有这种吗?
答案 0 :(得分:1)
您正在使用同步操作,它们阻止了事件循环,因此异步操作(例如网络连接)可能直到事件循环可用时才能继续进行。
您可以通过消除同步操作(用异步操作重写)来解决此问题,以便事件循环可以在循环期间进行操作。
这是一种使用异步I / O进行编码并使用async/await
来使循环更容易工作的方法:
const express = require('express');
const app = express();
const socketIO = require('socket.io');
const exec = require('child_process').exec;
const promisify = require('util').promisify;
const fsp = require('fs').promises;
const execP = promisify(exec);
app.post('/bootupserver', async function(req, res) {
progress = [];
io.emit('update', getCurrentServerState());
try {
const filePath = path.join(__dirname, 'bootserver.json');
const file = await fsp.readFile(filePath, { encoding: 'utf-8' });
progress = Object.values(JSON.parse(file));
for (let line of progress) {
line[0] = 1;
io.emit('update', getCurrentServerState());
await execP(line[2]);
line[0] = 2;
}
io.emit('update', getCurrentServerState());
res.sendStatus(200);
} catch(e) {
res.sendStatus(500);
}
});
我希望有一种冲洗/强制发射直接更新前端的机制。有这种吗?
不直接。您必须将循环的每个迭代放入setTimeout()
中(因此不能使用常规的for
或.forEach()
循环),以便让其他东西有运行的机会在运行循环的下一个迭代之前。更好的选择是仅切换到异步设计,以便所有内容可以协同运行。这就是设计node.js的方式。
如果您感到好奇,util.promisify()
会特别对待exec()
,以便其回调看起来像(err, stdio, stderr)
而不是标准的(err, value)
异步回调仍能正常工作(它将两个结果内部更改为{stdio, stderr}
,因此这是一个可以兑现承诺的值)。您没有使用这些返回的值,所以在这里没关系,但是如果您使用的话,它们仍然可以正常工作。