項目的頁面須要輪訓抓取數據,並且要支持暫停抓取,繼續抓取。還須要累計抓取的時間,以分鐘爲單位。前端
通常狀況下,前端多數是用setTimeout或者setInterval去每一秒對一個變量累計加1,而後除以60,就能夠獲得以分鐘爲單位的累計時間,就像這樣:函數
let second = 0;
let minute = 0;
setInterval(() => {
second += 1;
minute = Math.floor(second / 60); // 分鐘
}, 1000);
複製代碼
這種狀況看起來好像沒問題,但熟悉js的同窗應該一眼就看出毛病了。由於js是單線程,每一個回調函數都要通過事件隊列才能到達主線程執行。oop
因此假如在事件隊列裏,有一個複雜耗時的事件在setInterval的回調函數以前,它須要花費超過1秒的時間才能完成的話,那麼setInterval的回調函數將會等待超過1秒才能執行。spa
這樣就會致使偏差的出現。 也就是說 second = 2的時候,它可能實際上已是4,5秒了。線程
顯然,上面的代碼偏差隨着時間的推移,偏差會愈來愈大。code
後面想了想,咱們可不能夠經過時間戳來作計算呢?隊列
就是 咱們開始的時候,記錄下開始抓取的時間戳(startDate),而後使用setTimeout每一秒記錄下當前的時間戳(currentDate)。而後用(當前的時間戳 減去 開始的時間戳)再除以 60 * 1000,再用Math.floor向下取整它們的結果,這樣就計算了累計抓取的分鐘數。代碼以下事件
setTimeout(function loopTimer() {
let currentDate = new Date();
minute = Math.floor((currentDate - startDate) / 60 * 1000);
setTimeout(loopTimer, 1000);
}, 1000);
複製代碼
按道理來講,這樣也是有時間偏差的。如上面所說,loopTimer可能不是準確的1秒後執行,但咱們不是用second += 1累計的方式去計算,而是用時間戳。因此只要setTimeout的定時間隔足夠短, minute = Math.floor((currentDate - startDate) / 60 * 1000)計算得越頻繁,minute就會越準確回調函數