You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 21:50:40