这里对socket io完全陌生。
我想发出从我的服务器上运行的循环中运行的数据。循环运行一段时间(几秒钟,最多几分钟),我想从我的节点服务器发出数据,然后我想在浏览器中的客户端可视化这些数据(使用chart js)。基本上是实时数据图表。
出现的问题是,显然只有在循环结束后才会触发发射器。据我所知,这是因为emit函数是异步的(非阻塞)。由于循环本身会一直阻塞,直到结束(最初使用的是while循环),所以只在之后触发异步调用。对,是这样?
while (CONDITION) {
...
io.emit('data update', DATA);
}现在我已经想出了我自己的解决方案,但它感觉很笨拙。我想知道是否有更好的,更多的书本上的方法来做到这一点。我现在做的是递归地调用循环步骤(最后我调用emit),作为对setTimeout()的回调,并将持续时间设置为0。
function loopStep() {
if (CONDITION) {
...
io.emit('data update', DATA);
setTimeout(loopStep,0)
}
}
setTimeout(loopStep,0);我的问题是,还有其他更好的方法吗?
编辑:
我被要求添加完整的代码。
以下是早期(循环)版本的完整代码(据我所知,必须在此处快速重建):
let stp = 0;
while (stp < maxLogStep) {
let new_av_reward;
var smallStep = 0;
while (smallStep < maxSmallStep) {
let ran1 = get_random();
let cum_prob = 0;
let chosen_action = pref.findIndex((el, i) => {
let pro = prob(i);
let result = pro + cum_prob > ran1;
cum_prob += pro;
return result;
})
let cur_reward = get_reward(chosen_action);
if (stp*maxSmallStep + smallStep == 0) {
new_av_reward = cur_reward
} else {
new_av_reward = prev_av_reward + (cur_reward - prev_av_reward) / (stp * maxSmallStep + smallStep)
}
let cur_prob = prob(chosen_action);
pref.forEach((element, index, array) => {
if (chosen_action === index) {
array[index] = element + stepSize * (cur_reward - new_av_reward) * (1 - cur_prob)
} else {
array[index] = element - stepSize * (cur_reward - new_av_reward) * (cur_prob)
}
});
prev_av_reward = new_av_reward;
smallStep++
}
io.emit('graph update', {
learnedProb: [prob(0), prob(1), prob(2)],
averageReward: new_av_reward,
step: stp * maxSmallStep + smallStep
});
stp++
};下面是setTimeout的递归函数:
function learnStep(stp, prev_av_reward) {
let new_av_reward;
if (stp < maxLogStep) {
var smallStep = 0;
while (smallStep < maxSmallStep) {
let ran1 = get_random();
let cum_prob = 0;
let chosen_action = pref.findIndex((el, i) => {
let pro = prob(i);
let result = pro + cum_prob > ran1;
cum_prob += pro;
return result;
})
let cur_reward = get_reward(chosen_action);
if (stp*maxSmallStep + smallStep == 0) {
new_av_reward = cur_reward
} else {
new_av_reward = prev_av_reward + (cur_reward - prev_av_reward) / (stp * maxSmallStep + smallStep)
}
let cur_prob = prob(chosen_action);
pref.forEach((element, index, array) => {
if (chosen_action === index) {
array[index] = element + stepSize * (cur_reward - new_av_reward) * (1 - cur_prob)
} else {
array[index] = element - stepSize * (cur_reward - new_av_reward) * (cur_prob)
}
});
prev_av_reward = new_av_reward;
smallStep++
}
io.emit('graph update', {
learnedProb: [prob(0), prob(1), prob(2)],
averageReward: new_av_reward,
step: stp * maxSmallStep + smallStep
});
setTimeout(learnStep, 0, stp + 1, new_av_reward);
};发布于 2021-11-28 04:21:13
如果您的目标是确保在emit完成并且客户端接收并确认该数据之前保持while循环,则可能需要考虑使用Promises和socket.io确认功能,如下例所示:
服务器端
io.on("connection", async (socket) => {
// ...
while (CONDITION) {
// ...
await new Promise((resolve, reject) => {
io.emit('data update', data, (ack) => {
//client acknowledged received
resolve(true)
});
});
}
});客户端
socket.on("data update", (data, fn) => {
console.log(data)
fn("ack");
});https://stackoverflow.com/questions/70134755
复制相似问题