不會停下來的Timer
網頁分頁在閒置模式也會持續運作
前情提要
因為專案的需求,要在分頁的閒置模式下(分頁是inactive或idle狀態),持續計時並偵測時間,原本以為用setInterval就好,後來才發現過一段時間之後,瀏覽器會將閒置模式的網頁做"暫停"。這時網頁的interval, timeout都會在大約5分鐘之後,以極度緩慢的速度作計時,例如原本是1秒更新一次,變成2~3秒更新一次,甚至是不做計時了。
因此必須想辦法讓網頁隨時處在"活動"的狀態,爬了一些資料才找到使用Worker這個API來實現這個方法,才終於做到能在閒置模式下正常運行的Timer了。
至於讓網頁持續醒著的其他方法,似乎還可以用伺服器端的資料持續傳輸到網頁,WebSocket這種方式來保持網頁的"清醒",那即便是閒置著,計時器應該是可以如期正常運作。
主要實作核心
主要搭配React做Timer的渲染更新
Web Worker
使用Worker作為"背景"中保持繼續運行的執行序。
Worker需要寫在另一個js檔(worker.js),這個worker.js我稱作"伺服器"端,而在想要使用這個Worker的地方,透過新建一個worker來使用(new Worker),使用worker的地方我稱之為"客戶端"。
這個worker的運作方式有點像是本地端可以使用的socket,worker.js撰寫的"伺服器端"在收到訊息之後,每一段時間發送message給worker的”客戶端”,強迫網頁做更新。
React hooks & components
react部分則是useWorkerTimer這個hook使用worker,在useEffect監聽來自worker的message,靠其定時發送的message做更新timer。
還加上了Timer常見的功能,像是暫停/開始、重設。
記得addTimeCb要存在ref中,在每次狀態更新後都會隨時更新這個callback,這樣才會正確觸發計時+1的呼叫。
實際Demo
總結
這個方法當初是用在「計算使用者的”閒置”時間,並在一段時間後自動登出」這個功能,Web Worker本身還有許多有趣的應用可以玩,尤其是"背景執行"這方面,善加利用Worker可以做到多核心處理(例如複雜的運算丟給Worker執行,再丟給UI做render),有機會可以深入研究看看喔。
參考
https://developer.mozilla.org/zh-TW/docs/Web/API/Web_Workers_API/Using_web_workers