3 回答

TA貢獻(xiàn)2041條經(jīng)驗(yàn) 獲得超4個(gè)贊
這就是這里的問(wèn)題 - 代碼不計(jì)算真實(shí)的時(shí)間差,它只是計(jì)算循環(huán)的迭代次數(shù):
let timer = setInterval(function () {
? ? now++;? ? // <-- problem
僅當(dāng)每秒運(yùn)行一次時(shí),此代碼才能正確設(shè)置now為當(dāng)前時(shí)間。但我們知道,當(dāng)選項(xiàng)卡處于非活動(dòng)狀態(tài)時(shí),它不會(huì)。在這種情況下,它只是計(jì)算循環(huán)運(yùn)行的次數(shù),與實(shí)際經(jīng)過(guò)的時(shí)間無(wú)關(guān)。setInterval()
為了解決這個(gè)問(wèn)題,我們必須now根據(jù)實(shí)時(shí)情況來(lái)確定。為此,讓我們轉(zhuǎn)而使用 JS 來(lái)計(jì)算時(shí)間戳(PHP 僅在頁(yè)面加載時(shí)渲染一次,因此如果您在循環(huán)內(nèi)使用它,它將保持固定在初始值):
// 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);
現(xiàn)在,即使迭代之間有 10 秒的暫停,delta也將是自頁(yè)面加載以來(lái)經(jīng)過(guò)的時(shí)間的真實(shí)度量。因此,即使用戶(hù)切換到另一個(gè)選項(xiàng)卡,每次循環(huán)運(yùn)行時(shí),它都會(huì)正確跟蹤時(shí)間,即使它不是每秒都發(fā)生。
那么這對(duì)您來(lái)說(shuō)意味著什么?
根據(jù)您的報(bào)告,JS 根本沒(méi)有在非活動(dòng)選項(xiàng)卡中運(yùn)行。在這種情況下,選項(xiàng)卡可能會(huì)一直處于登錄狀態(tài),遠(yuǎn)遠(yuǎn)超出了用戶(hù)應(yīng)該注銷(xiāo)的時(shí)間。但是,假設(shè)當(dāng)您切換回選項(xiàng)卡時(shí) JS 再次啟動(dòng),循環(huán)的第一次迭代將正確計(jì)算經(jīng)過(guò)的時(shí)間。如果超過(guò)您的注銷(xiāo)期限,您將被注銷(xiāo)。因此,即使該選項(xiàng)卡保持登錄狀態(tài)的時(shí)間比應(yīng)有的時(shí)間長(zhǎng),用戶(hù)也無(wú)法使用它,因?yàn)橐坏┧麄兦袚Q到該選項(xiàng)卡,他們就會(huì)被注銷(xiāo)。請(qǐng)注意,“盡快”實(shí)際上意味著“1 秒內(nèi)加上 AJAX 查詢(xún)成功注銷(xiāo)用戶(hù)所需的時(shí)間”。
在我的測(cè)試中,JS 不會(huì)在非活動(dòng)的 Safari 選項(xiàng)卡中停止,而是會(huì)減慢速度。在這種情況下,這意味著用戶(hù)將在非活動(dòng)選項(xiàng)卡上自動(dòng)注銷(xiāo),盡管不是在正確的時(shí)間。如果循環(huán)每 8 秒運(yùn)行一次,則可能意味著用戶(hù)將比應(yīng)有的時(shí)間晚 7 秒注銷(xiāo)。如果迭代減慢得更多,延遲可能會(huì)更大。假設(shè)用戶(hù)切換回選項(xiàng)卡后 JS 再次正常啟動(dòng),行為將與上面完全相同,在這種情況下的第一次迭代將注銷(xiāo)它們。
編輯
這是簡(jiǎn)化的完整代碼,以及顯示其運(yùn)行和工作的 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貢獻(xiàn)1864條經(jīng)驗(yàn) 獲得超2個(gè)贊
當(dāng)打開(kāi)多個(gè)選項(xiàng)卡時(shí),此方法將無(wú)法正常工作。如果用戶(hù)打開(kāi)新選項(xiàng)卡并開(kāi)始在其中工作,則較早的選項(xiàng)卡將注銷(xiāo)該用戶(hù),因?yàn)樵撚脩?hù)在該選項(xiàng)卡中不處于活動(dòng)狀態(tài)。
為了克服這個(gè)問(wèn)題,我建議使用 ajax 調(diào)用從服務(wù)器檢查上次活動(dòng)時(shí)間,而不是僅使用 javascript。

TA貢獻(xiàn)1833條經(jīng)驗(yàn) 獲得超4個(gè)贊
您可以用計(jì)算時(shí)間差來(lái)替換計(jì)數(shù)器(它計(jì)算秒數(shù))。
let lastActivity = new Date();
let logoutAfter = 3600;
...
let delta = (new Date()).getTime() - lastActivity.getTime();
if (delta > logoutAfter) {
...
}
PS 因此,即使選項(xiàng)卡處于非活動(dòng)狀態(tài)時(shí)腳本本身被凍結(jié),它也必須工作。當(dāng)用戶(hù)激活此選項(xiàng)卡時(shí),將調(diào)用間隔處理程序。
- 3 回答
- 0 關(guān)注
- 209 瀏覽
添加回答
舉報(bào)