1. 程式人生 > >h5頁面切換到後臺再返回 js 定時器時間不準確解決方法

h5頁面切換到後臺再返回 js 定時器時間不準確解決方法

這兩天做迭代任務遇到了一個難題,現在找到了解決方法,為了避免忘記,在這裡記錄下來。

專案描述:一個基於vue寫的 h5頁面,根據後端返回的當前伺服器時間做一個倒計時(我是用setInterval 做的)。該h5頁面分別巢狀到微信公眾號、和原生app中。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

問題描述:使用home鍵把頁面切到後臺執行,倒計時就暫停了,再切回到前臺執行回去看倒計時,時間不準確(具體表現為:切出之前是20:20:20,切出等待10秒再切回來,時間仍然停留在20:20:20,並沒有減去10秒)。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

我百度了一下,看到了一個大神的回答:

【 PC 上的 Firefox、Chrome 和 Safari 等瀏覽器,都會自動把未啟用頁面中的 JavaScript 定時器(setTimeout、setInterval)間隔最小值改為 1 秒以上。這是因為間隔很小的定時器一般用來做 UI 更新(例如用定時器實現的動畫),讓使用者不可見的頁面上的定時器跑慢一些,既節省資源又不會影響體驗。對移動瀏覽器來說,記憶體、CPU、頻寬等資源更加寶貴,移動裝置上的瀏覽器往往會直接凍結

所有未啟用頁面上的所有定時器。】

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

怎麼辦呢?

我立馬想到的是在定時器實時獲取當前伺服器時間,但這樣肯定不行,伺服器時間是通過介面獲取的,這樣就會大量造成伺服器的壓力。

後來想到可以監聽瀏覽器前後臺的切換狀態,這樣我們就可以可用這個狀態取去做一些事情了,比如切換回來的時候重新請求一下介面獲取伺服器時間再做倒計時,這樣既能大大減少了伺服器的壓力,又能得到準確的伺服器時間,從而讓倒計時變得準確無誤。

程式碼如下:

mounted() {

      let _this = this;

      document.addEventListener("visibilitychange", _this.checkViChange);  

},

methods: {

      checkViChange() {              if (!document.hidden) {                    this.getData();   //重新呼叫getData 方法去請求資料              }        }

}

這樣就能很好的捕抓瀏覽器的行為去拿資料了。

至少在pc端除錯的時候是沒有任何問題的。

-------------------------------------------------------------------------------這裡是分割線------------------------------------------------------------------------

以為pc端除錯OK就萬事大吉了麼?

心想著完美解決問題了的我,興高采烈的把程式碼把程式碼push上去,然後在公眾號看是OK的(微信有自己內建的瀏覽器,我自己認為它相當於pc端),再到app端看,竟然無動於衷!!不管你怎麼切出切入,硬是沒有監聽的到!!!真是令人崩潰,看來還要針對原生app做單獨處理。

我又去百度了一波,app從活動狀態轉入後臺,絕大部分app通常在幾秒內就從後臺變成了掛起。我想就是這個原因,導致我們的js 被阻塞了,停止運行了,所以我們寫好的監聽函式才監聽不到頁面的狀態。

這樣一來前端自己解決是不可能的了,只能讓app開發的小哥哥幫忙解決了,思路很簡單,app自己可以監聽的頁面的狀態,還能呼叫前端h5寫給它執行的方法,相當於把之前前端自己呼叫的方法讓app幫我們做。原生app與vue的互動可以參考這篇文章:https://blog.csdn.net/lvlemo/article/details/78905273

好了,那我們的程式碼就是下面這一小點,

mounted() {     let _this = this;     document.addEventListener("visibilitychange", _this.checkViChangeTotal);   //這是之前寫的監聽函式不用刪除     window.checkVisible = _this.checkVisible;  // checkVisible是寫給app呼叫的   },   methods: {     checkVisible: function(flag) {  // flag 是app 返回給我們的標識,告訴我們app現在處於什麼狀態,如 true是啟用,false是掛起       var _this = this;       if(flag) {         _this.getData();   // 啟用狀態重新獲取資料       }     }   }

到此為止,我們已經解決了app切到後臺執行倒計時不準的bug了!!真是值得慶幸的事情。

-------------------------------------------------------------------------------這裡是分割線------------------------------------------------------------------------

只是後面專案上線之後我們的測試小姐姐還發現了一個bug,就是iOS系統上面,長按螢幕仍然會導致倒計時暫停的問題。。我的天!!!但由於專案馬上就要投入使用了,所以我們組長大手一揮說不用改了,下次再做優化。

我後來在網上找了一下,原因是IOS機制的問題,將未啟用的頁面執行緒直接阻塞,怎麼解決這個問題呢,發現有人說可以用js worker來解決,思路是js worker可以構造出另一個執行緒出來,與我們的主執行緒並行,單獨做倒計時這一塊,但是相關文章很少,相關的demo更少,我只看到了一個基於jquery寫的單個倒計時的demo,然而我的頁面基於vue開發,有多個倒計時,我嘗試過改造,但是由於文件太少,參考價值不多,加上本人體力、智力不支,暫時放棄了繼續研究,有興趣的朋友可以研究一下,如果研究出來了希望能教教我,哈哈哈!先謝謝!

除了js worker的方法之外,其實我覺得同樣可以讓app幫忙處理的嘛!道理是同一個的,相信這不是什麼大問題。

這篇文章寫到這裡差不多了。基本記錄了我在這個小迭代中遇到的一些坑及解決辦法,以後就不怕忘記了。