当选项卡未激活时,保持 JS/jQuery 代码在 Safari 中正常工作

我有一个 JS/jQuery 代码,如下所示,其中我希望在会话选项卡不活动时保持 JS/jQuery 代码正常工作。


以下代码在 Google Chrome 中完美运行,但在 Safari 中不起作用。


jQuery(document).ready(function ($) {


    let lastActivity = <?php echo time(); ?>;  // Line A


    let now = <?php echo time(); ?>;


    let logoutAfter = 3600;   // page will logout after 1800 seconds if there is no activity


    let userName = "<?php echo $_SESSION['user_name']; ?>";


    let timer = setInterval(function () {

        now++;

        let delta = now - lastActivity;

        console.log(delta);  // Line A

        if (delta > logoutAfter) {

            clearInterval(timer);

            //DO AJAX REQUEST TO close.php

            $.ajax({

                url: "/control/admin.php",

                type: 'GET', // GET also fine

                data: {action: 'logout', user_name: userName},

                success: function (data) {

                    window.location.href = "admin.php";

                },

                error: function (jqXHR, textStatus, errorThrown) {

                    alert(textStatus);

                }

            });

        }

    }, 1000); //<-- you can increase it( till <= logoutAfter ) for better performance as suggested by @"Space Coding"

});

Line A当选项卡未处于活动状态时,Safari 中的值不会增加,但在 Google Chrome 中却可以正常工作。在 Google Chrome 中,它按预期工作。


慕仙森
浏览 141回答 3
3回答

缥缈止盈

这就是这里的问题 - 代码不计算真实的时间差,它只是计算循环的迭代次数:let timer = setInterval(function () {    now++;    // <-- problem仅当每秒运行一次时,此代码才能正确设置now为当前时间。但我们知道,当选项卡处于非活动状态时,它不会。在这种情况下,它只是计算循环运行的次数,与实际经过的时间无关。setInterval()为了解决这个问题,我们必须now根据实时情况来确定。为此,让我们转而使用 JS 来计算时间戳(PHP 仅在页面加载时渲染一次,因此如果您在循环内使用它,它将保持固定在初始值):// Note that JS gives us milliseconds, not secondslet lastActivity = Date.now();let now = Date.now();let logoutAfter = 3600 * 1000;let timer = setInterval(function () {    // PHP won't work, time() is rendered only once, on page load     // let now = <?php echo time(); ?>;    now = Date.now();    let delta = now - lastActivity;    console.log('New timer loop, now:', now, '; delta:', delta);现在,即使迭代之间有 10 秒的暂停,delta也将是自页面加载以来经过的时间的真实度量。因此,即使用户切换到另一个选项卡,每次循环运行时,它都会正确跟踪时间,即使它不是每秒都发生。那么这对您来说意味着什么?根据您的报告,JS 根本没有在非活动选项卡中运行。在这种情况下,选项卡可能会一直处于登录状态,远远超出了用户应该注销的时间。但是,假设当您切换回选项卡时 JS 再次启动,循环的第一次迭代将正确计算经过的时间。如果超过您的注销期限,您将被注销。因此,即使该选项卡保持登录状态的时间比应有的时间长,用户也无法使用它,因为一旦他们切换到该选项卡,他们就会被注销。请注意,“尽快”实际上意味着“1 秒内加上 AJAX 查询成功注销用户所需的时间”。在我的测试中,JS 不会在非活动的 Safari 选项卡中停止,而是会减慢速度。在这种情况下,这意味着用户将在非活动选项卡上自动注销,尽管不是在正确的时间。如果循环每 8 秒运行一次,则可能意味着用户将比应有的时间晚 7 秒注销。如果迭代减慢得更多,延迟可能会更大。假设用户切换回选项卡后 JS 再次正常启动,行为将与上面完全相同,在这种情况下的第一次迭代将注销它们。编辑这是简化的完整代码,以及显示其运行和工作的 JSFiddle。jQuery(document).ready(function($) {    let lastActivity = Date.now();    let now = Date.now();    let logoutAfter = 3600 * 1000;    let timer = setInterval(function() {            now = Date.now();        let delta = now - lastActivity;        console.log('New timer loop, now:', now, '; delta:', delta);            if (delta > logoutAfter) {            alert('logout!');        }    }, 1000); });

慕斯王

当打开多个选项卡时,此方法将无法正常工作。如果用户打开新选项卡并开始在其中工作,则较早的选项卡将注销该用户,因为该用户在该选项卡中不处于活动状态。为了克服这个问题,我建议使用 ajax 调用从服务器检查上次活动时间,而不是仅使用 javascript。

潇潇雨雨

您可以用计算时间差来替换计数器(它计算秒数)。let lastActivity = new Date();let logoutAfter = 3600;...let delta = (new Date()).getTime() - lastActivity.getTime();if (delta > logoutAfter) {&nbsp; &nbsp; ...}PS 因此,即使选项卡处于非活动状态时脚本本身被冻结,它也必须工作。当用户激活此选项卡时,将调用间隔处理程序。
打开App,查看更多内容
随时随地看视频慕课网APP