当用户离开(关闭)页面时如何发送AJAX请求?

问题描述:

The Situation

Hi, I'm making a database-driven game, in which there is a question, and a user gains the right to change the question (i.e. write a new question) if they find the correct answer.

But this has an important issue, I think it's called a race condition. The issue is this:

  • User 1 finds the answer
  • User 1 is prompted to enter a new question
  • Before User 1 submits the new question, User 2 finds the new answer too
  • Now it's only luck, who is submitting the new question. If User 2 submits the question after User 1, User 2's question overwrites User 1's question.

Right now, I've fixed this issue by using some kind of semaphore, by keeping its timestamp. To summarize it works like this:

  • User 1 finds the answer
  • Semaphore is saved into database like ['user_ip' = 'x.x' , 'time'='y.y' , 'locked'='true']
  • Semaphore expires after t seconds
  • New question will be accepted only if semaphore is expired.

so when a new question is submitted, the application accepts it only if the semaphore is not locked, and the current time is larger by t (15) seconds than the semaphore's date.

But this has a problem too, User 2 is prompted

"You have found the answer, but somebody found it before you. You can change the question if they don't submit a new question in 15 seconds."

So the new winner has to wait 15 seconds, maybe unnecessarily.

Therefore,

What I Want to Do

I want to prompt the "winner" a form, with a stopwatch (time counter). When it reaches zero, it unlocks the semaphore so that the new winner can submit their question.

But this solution will have this problem:

If the winner closes the page before time counter reaches to zero, then the AJAX request will never be done and the semaphore will be locked indefinitely.

So I have to make sure I have called the userLeave(); function if the user closes the page.

Google suggests onbeforeunload and onunload but people also complain about those functions not working. So is there a 100%-sure way to send this AJAX call if a user (a winner) leaves the page ?

情境 h2>

嗨, 我正在进行数据库驱动 游戏,其中有一个问题,如果用户找到正确的答案,用户有权更改问题(即写一个新问题)。 p>

但这有一个重要问题 ,我认为这被称为竞争条件。 问题是: p>

  • 用户1找到答案 li>
  • 提示用户1输入新问题 li>
  • 在用户1提交新问题之前,用户2也会找到新答案 li>
  • 现在只有运气,谁在提交新问题。 如果用户2在用户1之后提交问题,则用户2的问题将覆盖用户1的问题。 li> ul>

    现在,我通过使用某种信号量修复了此问题 ,保留 timestamp code>。 总结一下它是这样的: p>

    • 用户1找到答案 li>
    • 信号量被保存到数据库中,如 ['user_ip' ='xx','time'='yy','locked'='true'] code> li>
    • 信号量在t秒后过期 li>
    • 新问题 只有在信号量过期时才会被接受。 li> ul>

      所以当提交新问题时,只有当信号量不 strong时,应用程序才接受它 >已锁定,当前时间比信号量日期的 t code>(15)秒大。 p>

      但这也存在问题,提示用户2

      “你找到了答案,但有人在你面前找到了答案。如果他们在15秒后没有提交新问题,你可以改变问题 。“ p> blockquote>

      所以新的获胜者必须等待15秒,可能不必要。 p>

      因此, p> \ n

      我想做什么 h2>

      我想用秒表(时间计数器)提示“赢家”表格。 当它达到零时,它会解锁信号量,以便新的获胜者可以提交他们的问题。 p>

      但是这个解决方案会遇到这个问题: p>

      如果 胜利者在时间计数器达到零之前关闭页面,然后AJAX请求永远不会完成,信号量将被无限期锁定。 p>

      所以我必须确保我已经调用了 userLeave(); code>函数,如果用户关闭页面。 p>

      Google建议 onbeforeunload code>和 onunload code>但是人们 还抱怨这些功能不起作用。 如果用户(获胜者)离开页面,是否有100%的方式发送此AJAX调用? p> div>

Is there a 100%-sure way to send this AJAX call if a user (a winner) leaves the page?

You can never rely on the client doing anything 100%. Think of network connectivity losses, browser crashes, not available features (from HTML5-incompatible browsers to disabled javascript), scripting errors, misconfigured agents that do call (or not) your API in unexpected ways or hackers doing the same on purpose…

The only thing you can expect of a client is that he does nothing - which is called a timeout.

If you want your semaphore to expire at a certain time, you have to create the timer serverside. If you want, you can additionally abort the timer and expire immediatley when a client signals that he's not going to submit an answer (by whichever means). If you want to try to catch closing the page, you can use synchronous (A)JAX from an unload event.

Btw: While I don't know your game, it would be easier and probably more comfortable if you simply would accept both new questions :-)