Ajax并发
我有一个网络应用程序,其中有一个不断倒计时的计时器。同时,客户端频繁地与服务器检查以查看定时器是否添加了更多时间。代码看起来像这样:
function tick() {
// This function is called once every second
time -= 1;
redisplay(time);
};
function update(newtime) {
// This function is called whenever the ajax request
// to the server yields a new time
time = newtime;
};
当然,它比这更复杂一些,但是您可以看到固有的竞争条件。如果更新和刻度函数都尝试同时修改时间
怎么办?
坦率地说,我对 javascript 的了解还不够多,无法理解如何处理此类并发问题:是否有一种简单的方法可以做到这一点,或者如果没有,有人可以向我指出可以了解更多信息的资源吗?
谢谢。
I have a web application where there is a timer that is constantly counting down. Meanwhile, the client frequently checks with the server to see if more time has been added to the timer. The code looks something like this:
function tick() {
// This function is called once every second
time -= 1;
redisplay(time);
};
function update(newtime) {
// This function is called whenever the ajax request
// to the server yields a new time
time = newtime;
};
It is, of course, a bit more complex than that, but you can see the inherent race condition. What if the update and the tick function are both trying to modify time
at the same time?
Frankly, I don't know nearly enough javascript to understand how to deal with this sort of concurrency issue: is there an easy way to do this, or if not, can somebody point me towards resources where I can learn more?
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
你没有竞争条件,因为 Javascript 不会同时执行。
每次从异步操作(AJAX、setTimeout 等)触发回调时,该回调必须先完成执行,然后才能调用另一个异步操作的另一个回调。因此,如果
update()
正在运行,则没有其他 Javascript 正在运行。一旦update()
完成,就可以触发来自异步操作的其他回调(例如tick()
)。有趣的是,这也是为什么setTimeout
及其同类不能保证在达到超时的精确时刻执行:其他一些 javascript 可能会阻止回调的执行。查看 http://ejohn.org/blog/how-javascript-timers-work/ 了解有关这一切如何运作的一些有用信息。
You don't have a race condition, because Javascript doesn't execute concurrently.
Every time a callback is fired from an async operation (AJAX,
setTimeout
, etc), that callback must finish executing before another callback from another async operation can be called. So ifupdate()
is running, no other Javascript is. Onceupdate()
finishes, other callbacks from async operations can be fired (for example,tick()
). Interestingly enough, this is also whysetTimeout
and its ilk aren't guaranteed to execute at the precise moment the timeout is reached: some other javascript could be blocking the callback's execution.Check out http://ejohn.org/blog/how-javascript-timers-work/ for some good information on how all this works.
JavaScript 是单线程的。没有竞争条件。在 JavaScript 中,
time = newtime;
和time -= 1;
两行在执行过程中无法重叠。事实上,这两个功能是保证不重叠的。其中一个将运行,然后另一个将运行。Javascript is single threaded. There is no race condition. There's no way in javascript for the two lines
time = newtime;
andtime -= 1;
to overlap during execution. In fact, the two functions are guaranteed not to overlap. One of them will run and then the other will run.我错了:这并不能解决问题! (代码后的解释)
这个错误解决方案的问题在于,这样做只需将竞争条件问题从变量
time
移至变量NEWTIME
即可。试想一下:
tick
的执行到达并执行了time = NEWTIME;
行,现在,在继续之前,调用 update 并且NEWTIME
得到一个值X
。现在tick执行继续执行NEWTIME = false;
。这样你就失去了NEWTIME
的X
值,因此 update() 调用的效果!I was wrong: this does not solve the issue! (explaination after the code)
The problem with this wrong solution is that doing this way you just move the race condition issue from variable
time
to variableNEWTIME
.Just think this: the execution of
tick
reaches and executes the linetime = NEWTIME;
now, before continuing, update get called andNEWTIME
gets a valueX
. Now tick execution continues executingNEWTIME = false;
. This way you've lost theX
value ofNEWTIME
and so the effect of an update() call!该问题需要一些信号量。在前一个完成后发送 ajax 时,我经常这样做。你的情况有点相似;)
尝试类似的事情。它应该忽略所有与 ajax 回调冲突的减少时间的尝试。
另一件事 - setTimeout 的工作方式就像一个新线程,我希望浏览器能够同步内存访问,因此检查值在递减之前是否没有增长可能就足够了。但上述方案更加灵活、安全。
还有一个小技巧 - 避免过于频繁地使用 AJAX 进行查询 - 这可能会导致额外的问题 - 例如请求返回的顺序与发送的顺序不同,并且每分钟使用过多的 ajax 会导致 Firefox 内存使用量增加;)
The problem needs some semaphores. I do that a lot for sending ajax after previous one finishes. Your case is a bit alike ;)
Try something like that. It should ignore all attempts to decrement time that collide with ajax callback.
One more thing - the setTimeout works like a new thread and I would expect that browsers do the synchronising mem access, so It might be enough to check if the value didn't grow before decrementing. But the above solution is more flexible and safe.
And one little tip - avoid querying with AJAX too often - it may cause extra problems - like requests coming back in different order than sent, and firefox memory usage building up a lot on too much ajax a minute ;)
只要您在当前时间上再增加几秒,就应该没问题。
不要这样做
time = newtime;
尝试time += newtime;
这样你就不会失去你担心的那一秒。尽管如此,最坏的情况下你也只会损失一秒钟。
As long as you add some more seconds to you current time you should be fine.
Instead of doing
time = newtime;
trytime += newtime;
This way you will not lose the second you're worried about.Still, you are only losing a second at worst.