【问题标题】:$(window).unload wait for AJAX call to finish before leaving a webpage [duplicate]$(window).unload 在离开网页之前等待 AJAX 调用完成[重复]
【发布时间】:2011-03-09 11:39:08
【问题描述】:

基本上,一旦用户在我的应用程序中离开网页,我需要使用 AJAX 调用 PHP 脚本,它将在网页上花费的时间插入数据库,然后离开页面。

等待 AJAX 请求完成很重要,因为用户无法访问我的应用程序中的网页,除非他们在前一页上花费了一定时间(比如说两分钟)。

这是我的 jquery 代码:

$(document).ready(function() {

    var teid = TEID;
    var startTime = new Date().getTime();

    $(window).unload(function() {
        var timeSpentMilliseconds = new Date().getTime() - startTime;
        var t = timeSpentMilliseconds / 1000 / 60;

        $.ajax({
            type: 'POST',
            url: '/clientarea/utils/record-time',
            data: 'teid=' + teid + '&t=' + t
        });
    });

});

我应该如何更改它,以便在离开网页之前等待 AJAX 请求结束?

编辑:

或者让 AJAX 请求每分钟左右重复一次可能会更好(更容易)。这可能吗?

【问题讨论】:

    标签: javascript jquery ajax


    【解决方案1】:

    好吧,您可以在 AJAX 调用中设置 async: false 以使浏览器在执行其他任何操作之前等待请求完成,但请注意,这将在请求期间“挂起”浏览器。

    $.ajax({
        type: 'POST',
        async: false,
        url: '/clientarea/utils/record-time',
        data: 'teid=' + teid + '&t=' + t
    });
    

    来自手册:

    默认情况下,所有请求都是异步发送的(即默认设置为 true)。如果您需要同步请求,请将此选项设置为 false。跨域请求和 dataType: "jsonp" 请求不支持同步操作。请注意,同步请求可能会暂时锁定浏览器,从而在请求处于活动状态时禁用任何操作。

    ⚠ 警告:此答案于 2010 年发布,现已过时 - XHR specification 突出显示以下声明:

    worker 之外的同步 XMLHttpRequest 正在从 Web 平台中移除,因为它会对最终用户的体验产生不利影响。 (这是一个需要很多年的漫长过程。)当当前全局对象是 Window 对象时,开发人员不得为 async 参数传递 false。 强烈建议用户代理在开发人员工具中警告此类用法并且可能会尝试在发生“InvalidAccessError”DOMException 时抛出它。

    Chrome 中的 DevTools 最近开始警告它,因此这种变化(已经发生了几年)可能迫在眉睫。

    【讨论】:

    • 嗯。谢谢。我已经更新了我的问题。让 AJX 请求每隔一分钟重复一次可能会更容易。我该怎么做?
    • 我强烈建议避免这种情况,尤其是unload
    • 我发现总有比async: false更好的解决方案,不管问题如何。
    • 我在这个解决方案中看到的一个问题是请求在用户导航到的新页面中仍然有效。
    【解决方案2】:

    最好的解决方案是使用navigator.sendBeacon。这是全新的功能,开始在新版本的浏览器中实现。该功能在 Chrome 39 和 Firefox 31 之后的浏览器中可用。在撰写本文时,Internet Explorer 和 Safari 不支持该功能。为确保您的请求在尚不支持新功能的浏览器中发送,您可以使用以下解决方案:

    var navigator.sendBeacon = navigator.sendBeacon || function (url, data) {
      var client = new XMLHttpRequest();
      client.open("POST", url, false); // third parameter indicates sync xhr
      client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
      client.send(data);
    };
    

    希望这会有所帮助!

    【讨论】:

    • 我觉得这很优雅,我在 Electron 中使用它在应用关闭时发送数据
    • 2018年,这就是要走的路。
    【解决方案3】:

    在卸载处理程序中设置一个 cookie 怎么样?服务器应该在后续请求中看到它。

    <script>
        $(window).unload(function(){document.cookie='left_on='+(new Date())})
    </script>
    

    【讨论】:

    • 这是最好的解决方案。 • 用户不必等待 Ajax 请求。 • 数据将包含在对服务器的下一个请求中(一个请求,而不是两个)。 • 更少的代码。您可以将 cookie 设置为几秒钟后过期,并在页面加载后立即取消设置 cookie,以避免 GDPR 的隐私问题。
    【解决方案4】:

    对我来说,浏览器在关闭前等待不是一个好主意...
    仅仅是因为如果我真的想关闭它怎么办?...

    如果页面打扰了用户,那就不好了...

    我的建议是,在页面中,您等待 2 分钟(如果要求 2 分钟),然后发送用户已完成 2 分钟的 ajax...

    然后您可以在服务器端检查一个人是否有 2 分钟...

    【讨论】:

      【解决方案5】:

      尝试劫持用户的浏览器是个坏主意,因为这会给他们带来不好的感觉并将他们赶走。

      如果由于某种原因您不想在用户在前一个页面上花费最少时间之前不生成新页面,那么最好的做法是在服务器端进行试点,即重定向到当前页面直到请求的时间结束通过了。

      您甚至不需要进行 ajax 调用,只需在会话中存储页面提供时间的时间戳,并且在经过一定时间之前不要显示以下页面。

      一定要告诉用户他们必须等待新页面准备就绪,可能需要一个简单的 javascript 倒计时。

      如果您希望用户在一定时间内实际使页面处于活动状态(即不要切换到另一个选项卡/窗口等待两分钟过去),那么我无法提出有效的解决方案。

      【讨论】:

        【解决方案6】:

        使用onbeforeunload:

        $(document).ready(function(){
          window.onbeforeunload = function(){
             // $.ajax stuff here
             return false;
          }
        });
        

        这至少会给用户带来messagebox,询问他是否要关闭当前窗口/选项卡。

        【讨论】:

          【解决方案7】:

          我认为按照您的建议使用轮询技术会好得多,尽管它会在网络服务器上造成一些负载。

          $(document).ready(function() {
          
              var teid = TEID;
              var startTime = new Date().getTime();
          
              var ajaxFunc = function() {
                  var timeSpentMilliseconds = new Date().getTime() - startTime;
                  var t = timeSpentMilliseconds / 1000 / 60;
          
                  $.ajax({
                      type: 'POST',
                      url: '/clientarea/utils/record-time',
                      data: 'teid=' + teid + '&t=' + t
                  });
              };
          
              setInterval(ajaxFunc, 60000);
          
          })
          

          当你可以使用 websockets 时你会很高兴 :)

          【讨论】:

          • 谢谢。但这只会在一分钟后执行一次?它可以每分钟(60 秒)重复执行一次吗?
          • 这就是 setInterval 的作用,而不是 setTimeout
          【解决方案8】:

          jQuery.ajax() 方法有async 选项。如果将其设置为false,则调用将阻塞,直到响应返回(或超时)。我很确定,调用它会让浏览器在卸载处理程序中加载。

          旁注:您不能依靠它来工作。如果浏览器为用户提供取消卸载处理程序的选项(某些浏览器在等待一段时间后会这样做),则“在站点上花费的时间”将永远不会更新。您可以向站点添加一个计时器,该计时器会定期调用服务器上的脚本并更新时间。您不会有准确的值,但在您的情况下,这不是必需的。

          如果您只需要知道用户是否在页面上停留了 X 秒,您可以简单地在 onload 处理程序中设置一个超时时间(使用setTimeout(function, ms)),如果用户花费了所需的时间,它就会进行调用。所以不需要卸载处理程序。

          【讨论】:

            猜你喜欢
            • 2023-03-08
            • 2014-07-06
            • 1970-01-01
            • 2014-12-01
            • 2017-03-15
            • 2022-01-26
            • 1970-01-01
            • 1970-01-01
            • 2010-10-19
            相关资源
            最近更新 更多