Ajax并发

发布于 2024-08-18 10:40:43 字数 531 浏览 3 评论 0原文

我有一个网络应用程序,其中有一个不断倒计时的计时器。同时,客户端频繁地与服务器检查以查看定时器是否添加了更多时间。代码看起来像这样:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

栖迟 2024-08-25 10:40:43

你没有竞争条件,因为 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 if update() is running, no other Javascript is. Once update() finishes, other callbacks from async operations can be fired (for example, tick()). Interestingly enough, this is also why setTimeout 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.

东风软 2024-08-25 10:40:43

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; and time -= 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.

幸福%小乖 2024-08-25 10:40:43

我错了:这并不能解决问题! (代码后的解释)

NEWTIME = false;
function tick() {
    // This function is called once every second
    if (NEWTIME) {
        time = NEWTIME;
        NEWTIME = false;
    }
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    NEWTIME = newtime;
};

这个错误解决方案的问题在于,这样做只需将竞争条件问题从变量 time 移至变量 NEWTIME 即可。

试想一下: tick 的执行到达并执行了 time = NEWTIME; 行,现在,在继续之前,调用 update 并且 NEWTIME 得到一个值X。现在tick执行继续执行NEWTIME = false;。这样你就失去了 NEWTIMEX 值,因此 update() 调用的效果!

I was wrong: this does not solve the issue! (explaination after the code)

NEWTIME = false;
function tick() {
    // This function is called once every second
    if (NEWTIME) {
        time = NEWTIME;
        NEWTIME = false;
    }
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    NEWTIME = newtime;
};

The problem with this wrong solution is that doing this way you just move the race condition issue from variable time to variable NEWTIME.

Just think this: the execution of tick reaches and executes the line time = NEWTIME; now, before continuing, update get called and NEWTIME gets a value X. Now tick execution continues executing NEWTIME = false;. This way you've lost the X value of NEWTIME and so the effect of an update() call!

感情废物 2024-08-25 10:40:43

该问题需要一些信号量。在前一个完成后发送 ajax 时,我经常这样做。你的情况有点相似;)

尝试类似的事情。它应该忽略所有与 ajax 回调冲突的减少时间的尝试。

window.TimeKeeper = new function(){
this.time=0; //initial value, whatever
this.isopen=true;

this.decrement = function(){ 
 if(this.isopen){
  this.time--;
  redisplay(this.time);
  }
 }
this.set = function(val){
 if(this.isopen){
  this.isopen=false;
  this.time=val;
  this.isopen=true;
  } else {
  //another AJAX callback is modifying time. 
   //You can enqueue current value and put it later
  }
 }

}

function tick() {
    TimeKeeper.decrement();

};
function update(newtime) {
    TimeKeeper.set(newtime);
};

另一件事 - 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.

window.TimeKeeper = new function(){
this.time=0; //initial value, whatever
this.isopen=true;

this.decrement = function(){ 
 if(this.isopen){
  this.time--;
  redisplay(this.time);
  }
 }
this.set = function(val){
 if(this.isopen){
  this.isopen=false;
  this.time=val;
  this.isopen=true;
  } else {
  //another AJAX callback is modifying time. 
   //You can enqueue current value and put it later
  }
 }

}

function tick() {
    TimeKeeper.decrement();

};
function update(newtime) {
    TimeKeeper.set(newtime);
};

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 ;)

嘴硬脾气大 2024-08-25 10:40:43

只要您在当前时间上再增加几秒,就应该没问题。

不要这样做 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; try time += newtime; This way you will not lose the second you're worried about.

Still, you are only losing a second at worst.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文