[英]Calling asynchronous socket.io io.emit() in synchronous way
全新的插座 io 在這里。
我想發出從我在服務器上運行的循環中運行的數據。 循環運行一段時間(幾秒鍾,最多幾分鍾),我想從我的節點服務器發出數據,然后我想在瀏覽器的客戶端上可視化(使用圖表 js)。 基本上是實時數據圖表。
發生的問題是,顯然只有在循環完成后才會觸發發射。 據我了解,因為發出 function 是異步的(非阻塞)。 而且由於循環本身會阻塞直到完成(最初使用 while 循環),所以異步調用只會在之后觸發。 正確的?
while (CONDITION) {
...
io.emit('data update', DATA);
}
現在我想出了自己的解決方案,但感覺很笨拙。 我想知道是否有更好的,更多的書本方法來做到這一點。 我現在正在做的是遞歸調用循環步驟(最后我調用emit)作為對持續時間設置為0的setTimeout()的回調。
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:
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);
};
如果您的目標是確保在發出完成並且客戶端接收並確認該數據之前保持您的 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");
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.