我有一个用JS和socket.io编写的多用户聊天网页。
许多用户可以同时发送消息,当我收到一条消息时,我需要运行一个函数来更改DIV的innerHTML。
但是,假设要同时发送1000条消息,我想依次运行THAT函数。
即除非最后一次调用完成,否则不要对该函数运行另一个调用。 (并且该函数内的GLOBAL变量将不会被另一个SAME函数调用更改,直到当前调用完成为止)
例如(我通过使用计时器而不是socket.io事件来编写以下示例,因为它很容易理解)
下面是Javascript:
var gInteger = 0;
var gbolChanging = false;
function changeInteger (intChange) {
if (!gbolChanging) {
gbolChanging = true;
gInteger += intChange;
divInteger.innerHTML = gInteger;
gbolChanging = false;
}
}
var timer1 = setInterval(changeInteger, 1, 1);
var timer2 = setInterval(changeInteger, 1, -1);
<div id="divInteger">
</div>
上面是HTML:
上述html和js的预期结果是:
您应该只能看到0或1
实际结果是:
如果运行足够长的时间,您可能还会看到-1和2。 (即两个计时器都同时检测到bolChanging = false)
答案 0 :(得分:4)
Javascript不是多线程的,因此不能通过单独的事件同时调用同一函数。更一般而言,相同的变量不能同时由不同的指令访问(在线程环境中,两个线程访问的变量可能会在内存中重复,并且会发生同步问题)。
作为证明,请在事件处理程序中进行长时间的同步操作,以确保您的界面将冻结直到结束(并且无法处理其他事件)。
获得的结果不是同时调用该函数的结果,而是调用顺序是不可预测的的结果。
现在,您仍然可以通过使用某种信号量来确保顺序得到遵守:
var gInteger = 0;
var gbolWaitingForPlusOne = true;
var gbolWaitingForMinusOne = false;
var divInteger = document.getElementById('divInteger');
function changeInteger(intChange) {
if (
(gbolWaitingForPlusOne && intChange !== 1) ||
(gbolWaitingForMinusOne && intChange !== -1)
) {
return;
}
gbolWaitingForPlusOne = !gbolWaitingForPlusOne;
gbolWaitingForMinusOne = !gbolWaitingForMinusOne;
gInteger += intChange;
divInteger.innerHTML = gInteger;
// if you don't log you wont see because it's too fast
console.log(gInteger);
}
var timer1 = setInterval(changeInteger, 1, 1);
var timer2 = setInterval(changeInteger, 1, -1);
<div id="divInteger">0</div>
这仍然无法解决您的问题,因为这样消息会丢失。
您将不需要根据操作类型(+ 1 / -1)而是通过某种时间戳来进行累积和重新排序。在消息传递系统中,您将按消息的创建时间而不是它们的处理时间对消息进行重新排序。如果在同一时间(很可能)同时创建了两个或更多消息,则您将必须选择自己的显示顺序,但是没有充分的理由使同一创建的消息先于另一个出现日期(这实际上是javascript以“错误”顺序拨打电话时执行的操作)
答案 1 :(得分:0)
首先,谢谢remix23,我想我找到了对调用进行排序的答案,而不会丢失Array的调用:
var gintSumA = 0;
var gintSumB = 0;
var gintSumC = 0;
var gintSumAll = 0;
var gintToBeProcess = 0;
var timerWork, timerA, timerB, timerC;
var gintMax = 1000;
var gbolWorking = false;
var garrList = [];
function funStartAdd(strCaller, intNumber) {
switch (strCaller) {
case "A":
if (gintSumA < gintMax) {
garrList.push(intNumber);
gintSumA += intNumber;
gintToBeProcess += 1;
} else {
clearInterval(timerA);
}
break;
case "B":
if (gintSumB < gintMax) {
garrList.push(intNumber);
gintSumB += intNumber;
gintToBeProcess += 1;
} else {
clearInterval(timerB);
}
break;
case "C":
if (gintSumC < gintMax) {
garrList.push(intNumber);
gintSumC += intNumber;
gintToBeProcess += 1;
} else {
clearInterval(timerC);
}
break;
default:
// Do Nothing
}
}
function funActualAdd(intNumber) {
gintToBeProcess -= 1;
gintSumAll += intNumber;
}
function funWork() {
if (!gbolWorking) {
gbolWorking = true;
var intTemp = garrList[0];
garrList.splice(0,1);
funActualAdd(intTemp);
if (gintSumA == gintMax &&
gintSumB == gintMax &&
gintSumC == gintMax &&
gintToBeProcess == 0) {
// Display Result
divResult.innerHTML = "SumA = " + gintSumA + "<br/>" +
"SumB = " + gintSumB + "<br/>" +
"SumC = " + gintSumC + "<br/>" +
"SumAll = " + gintSumAll;
clearInterval(funWork);
}
gbolWorking = false;
}
}
timerA = setInterval(funStartAdd, 1, "A", 1);
timerB = setInterval(funStartAdd, 1, "B", 1);
timerC = setInterval(funStartAdd, 1, "C", 1);
timerWork = setInterval(funWork, 1);
<div id="divResult">
</div>