【问题标题】:setInterval pauses in Android Browser / Mobile Safari when screen times out屏幕超时时,setInterval 在 Android 浏览器/移动 Safari 中暂停
【发布时间】:2011-02-24 12:03:53
【问题描述】:

我为移动网络应用构建了一个基于 JavaScript 的简单计时器;举个例子:

var a = 0;
setInterval(function() {
    console.log('a', a);
    a++;
}, 1000);

这在 Mobile Safari 和 Android 浏览器中运行良好。它将每秒记录到控制台并相应地增加 a 的值。 (好吧,Android 浏览器不支持 console.log,但我们假设它支持。)

问题:如果屏幕超时(即用户停止与页面交互),setInterval 函数会暂停。当用户再次打开屏幕时,它会恢复。这对我不起作用,因为我需要计时器才能继续运行。

问题: 有没有办法防止 setInterval 函数在屏幕超时时暂停?如果没有,是否可以防止屏幕超时?还有其他选择吗?

提前致谢!

【问题讨论】:

    标签: javascript mobile-safari mobile-website setinterval android-browser


    【解决方案1】:

    您可以使用 Page Visibility API 来检测页面何时隐藏或可见。例如,如果用户离开浏览器并再次返回,或者屏幕关闭再打开。

    我用这个answer 来帮助创建解决方案。 您将需要存储您设置的时间间隔。然后,当 visibilityChange 事件侦听器指示文档再次可见时,您可以计算自第一次启动间隔以来经过的时间量,并根据需要更新数据。

    在我的例子中,我在我的 Angular2 项目中创建了一个倒数计时器。我的页面在 iPad 上运行,每当屏幕关闭时计时器就会暂停。所以我在ngOnInit() 中添加了事件监听器。然后,当屏幕重新打开时,我可以更新我的计时器以显示自启动以来所剩的正确时间。

    我正在使用 moment npm 包来处理我的日期时间。 timerInfo 对象是一个由间隔回调更新的类变量。 self.zone.run() 用于将更改传播到 DOM,以便显示更新的时间。

    用打字稿写的:

    private timerInfo:{
        days?:number,
        hours?:number,
        minutes:number,
        seconds:number
    };
    private startTime:Moment = moment();
    private timerDuration:number = 20;  // in minutes
    private timerHandle:any;
    
    ngOnInit() {
        this.setVisibilityListener();
    }
    
    private setVisibilityListener():void {
        var self = this;
        var hidden, visibilityState, visibilityChange;
    
        if (typeof document.hidden !== "undefined") {
            hidden = "hidden";
            visibilityChange = "visibilitychange";
            visibilityState = "visibilityState";
        }
    
        var document_hidden = document[hidden];
    
        document.addEventListener(visibilityChange, function () {
            if (document_hidden != document[hidden]) {
                if (document[hidden]) {
                    // Document hidden
                    console.log("document hidden");
                } else {
                    // Document shown
                    console.log("document shown; setCountDownTimer()");
                    self.setCountDownTimer();
                }
    
                document_hidden = document[hidden];
            }
        });
    }
    
    private setCountDownTimer():void {
        var self = this;
        if (self.startTime) {
            var startMoment = moment(self.startTime);
            var endMoment = startMoment.add(self.timerDuration, "minutes");
            console.log("endMoment: ", endMoment.toISOString());
    
            self.clearTimer();
    
            var eventTime = endMoment.unix();
            var currentTime = moment().unix();
            var diffTime = eventTime - currentTime;
            var duration = moment.duration(diffTime * 1000, 'milliseconds');
            var interval = 1000;
    
            // if time to countdown
            if (diffTime > 0) {
                self.timerHandle = setInterval(() => {
                    self.zone.run(() => {
                        var diff = duration.asMilliseconds() - interval;
                        if (diff < 0) {
                            self.clearTimer();
                            self.timerComplete();
                        } else {
                            duration = moment.duration(duration.asMilliseconds() - interval, 'milliseconds');
    
                            self.timerInfo = {
                                days: moment.duration(duration).days(),
                                hours: moment.duration(duration).hours(),
                                minutes: moment.duration(duration).minutes(),
                                seconds: moment.duration(duration).seconds()
                            };
                            // console.log("timerInfo: ", JSON.stringify(self.timerInfo));
                        }
                    });
                }, 1000);
            } else {
                self.timerComplete();
            }
        }
    }
    
    private clearTimer():void {
        if (this.timerHandle) {
            clearInterval(this.timerHandle);
            this.timerHandle = null;
        }
    }
    

    【讨论】:

      【解决方案2】:

      基本上没有。当屏幕超时时,手机会进入睡眠状态以节省电池电量。由于无论如何都看不到任何东西,因此停止了大量的处理任务。当您更改选项卡/窗口(页面从内存中卸载)时,也会发生类似的事情。目前无法通过 Web 应用程序请求设备保持开启状态。 Android 未来对访问硬件的支持可能会提供此功能,但我个人对此表示怀疑。

      如果您需要始终运行支持,则需要为两个系统编写本机应用程序(而且在 Android 上它可以始终运行)。

      【讨论】:

      • 我就是这么想的。感谢您的回答。
      猜你喜欢
      • 1970-01-01
      • 2019-04-15
      • 2015-08-24
      • 1970-01-01
      • 1970-01-01
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多