Javascript 防止浏览器被AJAX请求卡住

Javascript 防止浏览器被AJAX请求卡住,javascript,php,jquery,ajax,Javascript,Php,Jquery,Ajax,我当前正试图在用户关闭页面时发送请求。我正在使用onbeforeuload事件 该事件在选项卡关闭或页面刷新时触发。我的活动如下: window.onbeforeunload = function () { $.ajax({ //jQuery type: "POST", url: "offline.php", data: { logout: 'false' } }); }; offline

我当前正试图在用户关闭页面时发送请求。我正在使用
onbeforeuload
事件

该事件在选项卡关闭或页面刷新时触发。我的活动如下:

window.onbeforeunload = function () {
    $.ajax({ //jQuery
        type: "POST",
        url: "offline.php",
        data: {
            logout: 'false'
        }
    });
}; 
offline.php(这不是完整的脚本):

当用户关闭页面时,脚本将取消在聊天页面上设置的会话。三秒后,脚本应检查用户是否返回,但检查页面上的
会话。但是,当我按下刷新按钮时,问题出现了。刷新时,页面不会加载,因为三秒已完成。这会毁了我的整个系统

我尝试添加
ignore\u user\u abort(true)但它没有解决我的问题。有没有其他方法可以让它发挥作用

旁注:这是用来聊天的。当一个用户关闭页面时,它应该用“用户已离开”消息通知聊天室中的其他用户。刷新时不应显示此信息。当用户返回页面时,应通知其他用户该用户已返回并显示“用户已输入”消息

问题 很抱歉,您试图做的事情实际上是不可能的,因为有很多时候,
onbeforeuload
不会被调用,原因是浏览器实现、用户偏好、您的宠物斑马将您的计算机从桌面上撞下来等等

从Mozilla的卸载前
文档:

还要注意的是,各种移动浏览器会忽略事件的结果(也就是说,它们不会要求用户确认)。Firefox在about:config中有一个隐藏的首选项来执行相同的操作。本质上,这意味着用户始终确认可以卸载文档

解决方案 然而,这并不意味着无法处理离线用户

大多数聊天web应用程序使用心跳(类似于常规ping的请求),并使用最后一次ping之间的距离来确定用户断开连接。作为补充说明,我建议允许一个比三秒更宽的窗口来确定用户断开连接,因为ping可能无法在三秒的时间范围内完成,原因有很多

实施战略 您有几个选项可以实现ping。最常见的情况是,人们使用
window.setTimeout
调用ping,ping将在完成或失败时重新启动window.setTimeout,通常会在连续失败时将延迟加倍,这样就不会阻塞可能过载的服务

设置Ping超时: 那么window.setInterval呢?我的代码不会更短吗?
请不要那样做。我上面提到的关于“阻塞过载服务”的注释?如果这样做,情况会更糟。

我想指出,正如其他人所说,在页面卸载事件上执行AJAX请求是非常不可靠的

但是,您可能对Navigator.sendBeacon()感兴趣

相关摘录:

此方法解决了分析和诊断代码的需求,这些代码通常试图在卸载文档之前将数据发送到web服务器


它是实验性的,但一旦得到充分支持,就应该做你想做的事情。

你真的不应该指望
在卸载之前
在卸载之前
,因为浏览器不应该要求自己在用户关闭你的网页之前代表你做一些事情。如果真的这样做了,它将为恶意代码打开一条完整的攻击途径,你永远无法关闭一个页面(想想去torrent网站,每次单击任何DOM元素都会弹出2个页面,只是现在每次用户尝试关闭选项卡时,都会启动一个递归循环,防止他们离开而不会通过任务管理器关闭浏览器)

心跳 大多数聊天客户端使用心跳系统,客户端每x秒自动ping一次服务器。这种方法可行,但成本高昂且效率低下。你被迫不断地打开和关闭新连接,只是为了告诉服务器你仍在使用

双向信息传输 构建聊天系统的当代方式是使用web套接字。这些套接字是服务器在web浏览器和服务器之间建立的持久连接。在传统网页上,服务器总是对客户端所做的事情做出反应。客户端发出请求,服务器响应;此过程会重复自身一次又一次。服务器从不告诉客户端该做什么,然后等待客户端响应。有了web套接字,我们就没有了这种单向通信通道,而是有了一个允许双向通信的持续开放连接的管道

创建Web套接字 这不是一项琐碎的任务。为了让一些基本功能正常工作,您必须编写大量现成的样板代码。但好消息是,您不必这样做。有几个第三方JavaScript SDK/后端服务为您和客户封装了所有底层浏览器实现逻辑为您提供一个简单、清晰的界面。将它们与web套接字的关系视为jQuery与普通JavaScript的关系。它们为您标准化了所有内容,因此您不必担心编写低级web套接字实现和同步跨浏览器兼容性

我最喜欢的web套接字服务之一是。巧合的是,他们在网站上展示的是一个实时聊天应用程序,使用他们的服务提供的web套接字支持构建。如果您希望Firebase成为独立的数据库源,可以将其设置为独立的数据库源。或者,它可以简单地用作您的tr之间的通信媒介传统的SQL数据库(通过RESTful API与之通信)和客户机设备(浏览器、
...
unset($_SESSION["onpage"];
if ($_POST['logout'] == "false") {
    sleep(3);
    if (isset($_SESSION["onpage"]) || !empty($_SESSION["onpage"])) die();
}
...
var i = 1000;

(function ping() {
  $.ajax({
    type: "POST",
    url: "ping.php"
  }).done(function() {
    i = 1000;
    window.setTimeout(ping, i);
  }).fail(function() {
    i = i * 2;

    if (i > 60000) {
      // We don't wait to wait longer than a minute
      i = 60000;
    }

    window.setTimeout(ping, i);
  });
}());
window.addEventListener('unload', function () {

     navigator.sendBeacon("offline.php", {
         logout: 'false'
     });

}, false);