blog icon indicating copy to clipboard operation
blog copied to clipboard

手机浏览器在后台运行时会阻塞 JavaScript 进程

Open lmk123 opened this issue 9 years ago • 0 comments

最近开发了 Runner 用来记录我跑步时的进度,但却被一个问题给难住了。

比如下面这段代码:

let sec = 0;
setInterval( ()=> {
  sec += 1;
  if(sec === 55) { alert('notice me'); } // 在第 55 秒的时候提醒我
}, 1000 );

当浏览器处于后台运行时(例如用户关闭了屏幕、切换到了主屏幕或其它 APP),大概经过 17 秒后,浏览器就会停止计时函数。这就导致在经过了很长一段时间后,当用户重新切换回浏览器时,却发现网页上显示的是 17 秒,在这之后,计时函数又重新开始继续运行。

这个行为就好像是被 window.alert() 这一类的函数阻塞了 JavaScript 进程一样。

如果只是要修正计时器的读数其实并不难:

let sec = 0;
let now = Date.now();
setInterval( ()=> {
  const diff = Date.now() - now;
  if (diff > 1000) { // 具体数值可能有偏差
    sec += Math.floor(diff / 1000);
  } else {
    sec += 1;
  }
  now = Date.now();
}, 1000 );

但我想要的效果是:在某个时间点(比如第 55 秒的时候)播放一段声音提醒我。如果计时开始后手机屏幕被关闭了,那除非解锁手机,否则计时器永远不会到达第 55 秒。

我谷歌了很长时间,看起来唯一的解决方案是使用 NoSleep.js 让手机屏幕常亮,但我在 Runner 里试了好几次也没有成功。

然而有一次在给同事演示计时中断这个现象的时候,却发现最开始的那段代码在微信(iPhone 6s,iOS 9.3.1,微信 6.3.15)里可以正常计时——因为再次打开屏幕的时候,屏幕上出现了 notice me 的 alert 框,秒数正好停在 55 秒(因为 alert 函数也阻塞了 JavaScript 进程)。

现在还不太确定微信的 webview 是否真的不会在后台运行时阻塞 JavaScript 进程——说不定它会在 17 分钟后阻塞呢?但就在我要放弃使用 Runner 的时候,微信无疑成了最后一根稻草。

lmk123 avatar Apr 14 '16 16:04 lmk123