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也将是自页面加载以来经过的时间的真实度量。因此,即使用户切换到另一个选项卡,每次循环运行时,它都会正确跟踪时间,即使它不是每秒都发生。
那么这对您来说意味着什么?
根据您的报告,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);
});
TA贡献1864条经验 获得超2个赞
当打开多个选项卡时,此方法将无法正常工作。如果用户打开新选项卡并开始在其中工作,则较早的选项卡将注销该用户,因为该用户在该选项卡中不处于活动状态。
为了克服这个问题,我建议使用 ajax 调用从服务器检查上次活动时间,而不是仅使用 javascript。
TA贡献1833条经验 获得超4个赞
您可以用计算时间差来替换计数器(它计算秒数)。
let lastActivity = new Date();
let logoutAfter = 3600;
...
let delta = (new Date()).getTime() - lastActivity.getTime();
if (delta > logoutAfter) {
...
}
PS 因此,即使选项卡处于非活动状态时脚本本身被冻结,它也必须工作。当用户激活此选项卡时,将调用间隔处理程序。
- 3 回答
- 0 关注
- 136 浏览
添加回答
举报