JavaScript、浏览器、窗口关闭-发送AJAX请求或在窗口关闭时运行脚本

JavaScript、浏览器、窗口关闭-发送AJAX请求或在窗口关闭时运行脚本,javascript,browser,window,dom-events,Javascript,Browser,Window,Dom Events,我试图找出用户何时离开指定页面。找出他何时使用页面内的链接来导航是没有问题的,但我需要做一些标记,比如当他关闭窗口或键入另一个URL并按下enter键时。第二个并不重要,但第一个很重要。问题是: 当用户关闭我的页面(capture window.close事件),然后。。。这并不重要(我需要发送一个AJAX请求,但如果我能让它运行警报,我可以完成其余的工作)。使用: <body onUnload="javascript:"> 它应该捕获除关闭浏览器程序之外的所有内容。有卸载和卸

我试图找出用户何时离开指定页面。找出他何时使用页面内的链接来导航是没有问题的,但我需要做一些标记,比如当他关闭窗口或键入另一个URL并按下enter键时。第二个并不重要,但第一个很重要。问题是:

当用户关闭我的页面(capture window.close事件),然后。。。这并不重要(我需要发送一个AJAX请求,但如果我能让它运行警报,我可以完成其余的工作)。

使用:

<body onUnload="javascript:">


它应该捕获除关闭浏览器程序之外的所有内容。

卸载
卸载前
javascript事件,但这些事件对于Ajax请求来说并不可靠(不能保证在其中一个事件中启动的请求会到达服务器)

因此,强烈建议不要这样做,您应该寻找替代方案

如果你确实需要这个,考虑一个“ping”样式的解决方案。每分钟发送一个请求,基本上告诉服务器“我还在这里”。然后,如果服务器不接受这样的请求超过两分钟(您必须考虑延迟等),则认为客户端离线。



另一种解决方案是使用
unload
beforeunload
执行Sjax请求(同步JavaScript和XML),但这是完全不推荐的。这样做基本上会冻结用户的浏览器,直到请求完成为止,这是他们不喜欢的(即使请求只需要很少的时间)。

我同意Felix的想法,我已经用该解决方案解决了我的问题,现在我想清除服务器端解决方案:

1.从客户端向服务器发送请求

2.保存变量中接收到的最后一个请求的时间

3.检查服务器时间,并将其与上次接收的变量进行比较 请求

4.如果结果超出预期时间,则开始运行
您希望在windows关闭时运行的代码…

我还希望实现相同的功能&这是Felix给出的答案(不保证在这些事件中启动的请求会到达服务器

为了使请求到达服务器,我们尝试了以下代码:-

onbeforeunload = function() {

    //Your code goes here.

    return "";
} 

我们正在使用IE浏览器&现在,当用户关闭浏览器时,由于
return'',他会得到确认对话框&等待用户确认&此等待时间使请求到达服务器。

所选答案正确,您不能保证浏览器发送xhr请求,但根据浏览器的不同,您可以在选项卡或窗口关闭时可靠地发送请求

通常,浏览器在xhr.send()实际执行之前关闭。Chrome和edge看起来像是在关闭窗口之前等待javascript事件循环清空。它们也在与javascript事件循环不同的线程中触发xhr请求。这意味着,如果可以将事件循环保持足够长的时间,xhr将成功触发。例如,我测试了发送一个xhr请求,然后计数到100000000。对我来说,这在chrome和edge上都非常有效。如果您使用的是angularjs,那么在$apply中封装对$http的调用也可以实现同样的效果

看起来有点不一样。我认为IE不会等待事件循环为空,甚至不会等待当前堆栈帧为空。虽然它偶尔会正确地发送请求,但似乎更经常发生的情况(80%-90%)是IE会在xhr请求完全执行之前关闭窗口或选项卡,这只会导致发送部分消息。基本上,服务器接收post请求,但没有主体

下面是我作为window.onbeforeunload侦听器函数附加的代码:

  var xhr = new XMLHttpRequest();
  xhr.open("POST", <your url here>);
  xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
  var payload = {id: "123456789"};
  xhr.send(JSON.stringify(payload));

  for(var i = 0; i < 100000000; i++) {}
var xhr=new-XMLHttpRequest();
xhr.open(“POST”);
setRequestHeader(“内容类型”,“应用程序/json;字符集=UTF-8”);
var有效负载={id:“123456789”};
send(JSON.stringify(payload));
对于(var i=0;i<100000000;i++){
我参加了以下考试:

铬61.0.3163.100

IE 11.608.15063.0CO

Edge 40.15063.0.0)如果您正在寻找一种在所有浏览器中工作的方法,那么最安全的方法是向服务器发送同步AJAX。这不是一个好方法,但至少要确保您没有向服务器发送太多数据,并且服务器速度很快

2) 您还可以使用异步AJAX请求,并在服务器上使用ignore_user_abort函数(如果您使用的是PHP)。然而,忽略用户中止在很大程度上取决于服务器配置。确保你测试得很好

3) 对于现代浏览器,不应发送AJAX请求。您应该使用新的navigator.sendBeacon方法将数据异步发送到服务器,而不会阻止下一页的加载。由于您希望在用户移出页面之前将数据发送到服务器,所以可以在卸载事件处理程序中使用此方法

$(window).on('unload', function() {
    var fd = new FormData();
    fd.append('ajax_data', 22);
    navigator.sendBeacon('ajax.php', fd);
});
似乎还有一个问题。如果方法本机不可用,它会发送一个同步AJAX

对于移动设备很重要:请注意,卸载事件处理程序不保证为移动设备启动。但是visibilitychange事件肯定会被触发。因此,对于移动设备,您的数据收集代码可能需要进行一些调整

有关所有3种方式的代码实现,请参阅my。

2021年更新 TL;博士 是这个问题的解决办法

即使用户退出页面,信标请求也应该完成

你应该什么时候触发你的信标请求

这将取决于您的用例。如果您希望捕获任何用户退出,
visibilitychange
(而不是
unloa
# lifecycle.js (1K) for cross-browser compatibility
# https://github.com/GoogleChromeLabs/page-lifecycle

<script defer src="/path/to/lifecycle.js"></script>
<script defer>
lifecycle.addEventListener('statechange', function(event) {

  if (event.originalEvent == 'visibilitychange' && event.newState == 'hidden') {
    var URL = "https://example.com/foo";
    var data = "bar";

    navigator.sendBeacon(URL, data);
  }
});
</script>
    var URL = "https://example.com/foo";
    var data = "bar";

    navigator.sendBeacon(URL, data);
document.addEventListener('visibilitychange', function() {
      
  if (document.visibilityState == 'hidden') {
    
     // send beacon request
  }

});
# lifecycle.js (1K) for cross-browser compatibility
# https://github.com/GoogleChromeLabs/page-lifecycle

<script defer src="/path/to/lifecycle.js"></script>
<script defer>
lifecycle.addEventListener('statechange', function(event) {

  if (event.originalEvent == 'visibilitychange' && event.newState == 'hidden') {
    var URL = "https://example.com/foo";
    var data = "bar";

    navigator.sendBeacon(URL, data);
  }
});
</script>
$(window).bind('mouseover', (function () { // detecting DOM elements
    window.onbeforeunload = null;
}));

$(window).bind('mouseout', (function () { //Detecting event out of DOM
      window.onbeforeunload = ConfirmLeave;
}));

function ConfirmLeave() {
   if (performance.navigation.type == 1) { //detecting refresh page(doesnt work on every browser)
   }
   else {
       logOutUser();
   }
}

$(document).bind('keydown', function (e) { //detecting alt+F4 closing
    if (e.altKey && e.keyCode == 115) {
        logOutUser();
    }    
});
function logOutUser() {
   $.ajax({
     type: "POST",
     url: GWA("LogIn/ForcedClosing"), //example controller/method
     async: false
   });
}
 io.on('connection', function(socket){
      socket.on('disconnect', function(){
          // Do stuff here
      });
 });