为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PHP
慕仙森 2023-08-19 10:22:07
我有一个 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 中,它按预期工作。
查看完整描述

3 回答

?
缥缈止盈

TA贡献2041条经验 获得超4个赞

这就是这里的问题 - 代码不计算真实的时间差,它只是计算循环的迭代次数:

let timer = setInterval(function () {

    now++;    // <-- problem

仅当每秒运行一次时,此代码才能正确设置now为当前时间。但我们知道,当选项卡处于非活动状态时,它不会。在这种情况下,它只是计算循环运行的次数,与实际经过的时间无关。setInterval()


为了解决这个问题,我们必须now根据实时情况来确定。为此,让我们转而使用 JS 来计算时间戳(PHP 仅在页面加载时渲染一次,因此如果您在循环内使用它,它将保持固定在初始值):


// Note that JS gives us milliseconds, not seconds

let 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也将是自页面加载以来经过的时间的真实度量。因此,即使用户切换到另一个选项卡,每次循环运行时,它都会正确跟踪时间,即使它不是每秒都发生。

那么这对您来说意味着什么?

  1. 根据您的报告,JS 根本没有在非活动选项卡中运行。在这种情况下,选项卡可能会一直处于登录状态,远远超出了用户应该注销的时间。但是,假设当您切换回选项卡时 JS 再次启动,循环的第一次迭代将正确计算经过的时间。如果超过您的注销期限,您将被注销。因此,即使该选项卡保持登录状态的时间比应有的时间长,用户也无法使用它,因为一旦他们切换到该选项卡,他们就会被注销。请注意,“尽快”实际上意味着“1 秒内加上 AJAX 查询成功注销用户所需的时间”。

  2. 在我的测试中,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); 

});


查看完整回答
反对 回复 2023-08-19
?
慕斯王

TA贡献1864条经验 获得超2个赞

当打开多个选项卡时,此方法将无法正常工作。如果用户打开新选项卡并开始在其中工作,则较早的选项卡将注销该用户,因为该用户在该选项卡中不处于活动状态。

为了克服这个问题,我建议使用 ajax 调用从服务器检查上次活动时间,而不是仅使用 javascript。

查看完整回答
反对 回复 2023-08-19
?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

您可以用计算时间差来替换计数器(它计算秒数)。


let lastActivity = new Date();

let logoutAfter = 3600;

...

let delta = (new Date()).getTime() - lastActivity.getTime();

if (delta > logoutAfter) {

    ...

}

PS 因此,即使选项卡处于非活动状态时脚本本身被冻结,它也必须工作。当用户激活此选项卡时,将调用间隔处理程序。


查看完整回答
反对 回复 2023-08-19
  • 3 回答
  • 0 关注
  • 100 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信