Ext.TaskManager.newTask()在iPad锁屏时失效问题求助
iPad锁屏后会话倒计时失效的解决方案
问题核心是iOS Safari在页面后台(锁屏属于后台状态)会大幅节流甚至暂停setInterval这类定时器,导致你的task倒计时任务无法按时执行,直到解锁后才继续运行。以下是针对性的修复方案:
1. 重构倒计时逻辑,基于时间戳计算剩余时间
不要依赖定时器的每秒触发来累加时间,而是每次执行时直接用弹窗显示的初始时间和当前时间的差值,计算真实剩余时间。这样即使定时器被延迟,也能得到准确的倒计时,并且能立即判断是否已经过期。
修改后的task任务代码:
//Task to show the timeout count-down var task = Ext.TaskManager.newTask({ run: function () { var currentTime = Ext.Date.now(); var actualTimeout = uiSessionExpiryTimeInMin*60 - uiSessionExpiryPromptIntervalInMin*60; var timeDifference = Math.floor((currentTime - initialPopUpTime)/1000); // 直接判断是否已经过期,不用等定时器一步步走 if(timeDifference >= actualTimeout) { sessionTimeOutTask.delay(0); task.stop(); // 停止倒计时任务 return; } sessionTimeOutCountDown = actualTimeout - timeDifference; var countdownMinutes = Math.floor((sessionTimeOutCountDown)/(60)); var countdownSeconds = sessionTimeOutCountDown - (countdownMinutes * 60) + ' second(s)'; countdownMinutes = countdownMinutes === 0 ? '' : `${countdownMinutes} minute(s) and `; sessionAboutToTimeoutMessageBox.updateText( Ext.String.format(timeoutConfirmationtMessage, countdownMinutes, countdownSeconds) ); }, interval: 1000, scope:me });
2. 增加会话过期的兜底检查
在sessionAboutToTimeoutPromptTask的运行逻辑里,先检查是否已经超过了会话总过期时间,避免因为定时器被暂停,导致会话过期逻辑完全不触发:
var sessionAboutToTimeoutPromptTask =Ext.TaskManager.newTask( { run: function(){ var currentTime = Ext.Date.now(); // 先检查是否已经直接过期,跳过弹窗逻辑 var totalSessionExpiryTime = uiCheckTime + uiSessionExpiryTimeInMin*60*1000; if(currentTime >= totalSessionExpiryTime) { sessionTimeOutTask.delay(0); sessionAboutToTimeoutPromptTask.stop(); return; } if(currentTime >= uiCheckTime + uiSessionExpiryPromptIntervalInMin*60*1000 && !uiPromptMsg) { uiPromptMsg = true; sessionAboutToTimeoutMessageBox.show({ message : promptMsg(), buttons : Ext.Msg.YES, buttonText : { yes : "<span osviewid = 'OS_USER_SESSION_EXTEND_YES'>Yes</span>" }, fn : function(btn, text) { sessionTimeOutCountDown = uiSessionExpiryTimeInMin - uiSessionExpiryPromptIntervalInMin; if (btn == 'yes') { uiPromptMsg= false; uiCheckTime = Ext.Date.now(); resetTimeout(); extendSessionAjaxRequest(false); } } }); } }, interval:1000, scope:me });
3. 进阶方案:用Web Worker规避定时器限制
如果需要更稳定的计时,可以把倒计时逻辑放到Web Worker中——Web Worker在后台不会被浏览器节流,能保持稳定的计时。注意Worker不能直接操作DOM,只能通过消息通知主线程更新UI或触发过期。
1) 创建Worker文件(timeout-worker.js)
let timerId; self.onmessage = function(e) { if(e.data.type === 'start') { const { initialTime, actualTimeout } = e.data; timerId = setInterval(() => { const currentTime = Date.now(); const timeDifference = Math.floor((currentTime - initialTime)/1000); if(timeDifference >= actualTimeout) { self.postMessage({type: 'expired'}); clearInterval(timerId); } else { self.postMessage({type: 'update', remaining: actualTimeout - timeDifference}); } }, 1000); } }; self.onmessage = function(e) { if(e.data.type === 'stop') { clearInterval(timerId); } };
2) 主线程中调用Worker
修改promptMsg函数,用Worker替代原来的task:
var promptMsg = function () { initialPopUpTime = Ext.Date.now(); var actualTimeout = uiSessionExpiryTimeInMin*60 - uiSessionExpiryPromptIntervalInMin*60; // 创建Worker并启动计时 const timeoutWorker = new Worker('timeout-worker.js'); timeoutWorker.postMessage({ type: 'start', initialTime: initialPopUpTime, actualTimeout: actualTimeout }); // 监听Worker消息 timeoutWorker.onmessage = function(e) { if(e.data.type === 'expired') { sessionTimeOutTask.delay(0); timeoutWorker.terminate(); } else if(e.data.type === 'update') { sessionTimeOutCountDown = e.data.remaining; var countdownMinutes = Math.floor((sessionTimeOutCountDown)/(60)); var countdownSeconds = sessionTimeOutCountDown - (countdownMinutes * 60) + ' second(s)'; countdownMinutes = countdownMinutes === 0 ? '' : `${countdownMinutes} minute(s) and `; sessionAboutToTimeoutMessageBox.updateText( Ext.String.format(timeoutConfirmationtMessage, countdownMinutes, countdownSeconds) ); } }; // 初始文本计算 var countdownMinutes = Math.floor((sessionTimeOutCountDown)/(60)); var countdownSeconds = sessionTimeOutCountDown - (countdownMinutes * 60) + ' second(s)'; countdownMinutes = countdownMinutes === 0 ? '' : `${countdownMinutes} minute(s) and `; return Ext.String.format(timeoutConfirmationtMessage, countdownMinutes, countdownSeconds); }; // 记得在resetTimeout里停止Worker var resetTimeout = function(){ sessionTimeOutTask.cancel(); sessionAboutToTimeoutPromptTask.stop(); // 如果存在Worker,发送停止消息并终止 if(typeof timeoutWorker !== 'undefined') { timeoutWorker.postMessage({type: 'stop'}); timeoutWorker.terminate(); } resetTimer(); }
核心原理
iOS Safari对后台页面的定时器有严格限制,setInterval的执行间隔会被拉长到1分钟以上,甚至直接暂停。所以所有时间相关逻辑必须基于绝对时间戳的差值计算,而不是依赖定时器的执行次数累加时间,这样即使定时器被延迟,也能得到准确的剩余时间和过期判断。
内容的提问来源于stack exchange,提问作者user9511333
相关产品推荐
相关产品推荐

