<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文是深入淺出 ahooks 原始碼系列文章的第七篇,這個系列的目標主要有以下幾點:
注:本系列對 ahooks 的原始碼解析是基於 v3.3.13
。自己 folk 了一份原始碼,主要是對原始碼做了一些解讀,可見 詳情。
今天我們來聊聊定時器。
看名稱,我們就能大概知道,它們的功能對應的是 setInterval 和 setTimeout,那對比後者有什麼優勢?
先看 useInterval
,程式碼簡單,如下所示:
function useInterval( fn: () => void, delay: number | undefined, options?: { immediate?: boolean; }, ) { const immediate = options?.immediate; const fnRef = useLatest(fn); useEffect(() => { // 忽略部分程式碼... // 立即執行 if (immediate) { fnRef.current(); } const timer = setInterval(() => { fnRef.current(); }, delay); // 清除定時器 return () => { clearInterval(timer); }; // 動態修改 delay 以實現定時器間隔變化與暫停。 }, [delay]); }
跟 setInterval 的區別如下:
useTimeout 跟上面很類似,如下所示,不再做額外解釋:
function useTimeout(fn: () => void, delay: number | undefined): void { const fnRef = useLatest(fn); useEffect(() => { // ...忽略部分程式碼 const timer = setTimeout(() => { fnRef.current(); }, delay); return () => { clearTimeout(timer); }; // 動態修改 delay 以實現定時器間隔變化與暫停。 }, [delay]); }
首先,setTimeout 和 setInterval 作為事件迴圈中宏任務的“兩大主力”,它的執行時機不能跟我們預期一樣準確的,它需要等待前面任務的執行。比如下面的 setTimeout 的第二個引數設定為 0,並不會立即執行。
setTimeout(() => { console.log('test'); }, 0)
另外還有一種情況,setTimeout 和 setInterval 在瀏覽器不可見的時候(比如最小化的時候),不同的瀏覽器中設定不同的時間間隔的時候,其表現不一樣。根據 當瀏覽器切換到其他分頁或者最小化時,你的js定時器還準時嗎? 這篇文章的實踐結論如下:
谷歌瀏覽器中,當頁面處於不可見狀態時,setInterval 的最小間隔時間會被限制為 1s。火狐瀏覽器的 setInterval 和谷歌特性一致,但是 ie 瀏覽器沒有對不可見狀態時的 setInterval 進行效能優化,不可見前後間隔時間不變。
在谷歌瀏覽器中,setTimeout在瀏覽器不可見狀態下間隔低於1s的會變為1s,大於等於1s的會變成N+1s的間隔值。火狐瀏覽器下setTimeout的最小間隔時間會變為1s,大於等於1s的間隔不變。ie瀏覽器在不可見狀態前後的間隔時間不變。
這個結論,我沒有驗證過,但看起來差異挺大,其中還提到了另外一個選擇,就是 requestAnimationFrame。
window.requestAnimationFrame() 告訴瀏覽器——你希望執行一個動畫,並且要求瀏覽器在下次重繪之前呼叫指定的回撥函數更新動畫。該方法需要傳入一個回撥函數作為引數,該回撥函數會在瀏覽器下一次重繪之前執行
為了提高效能和電池壽命,因此在大多數瀏覽器裡,當requestAnimationFrame() 執行在後臺分頁或者隱藏的 <iframe>
裡時,requestAnimationFrame() 會被暫停呼叫以提升效能和電池壽命。
所以,ahooks 也提供了使用 requestAnimationFrame
進行模擬定時器處理的 hook,我們一起來看下。
直接看 useRafInterval
。(useRafTimeout 和 useRafInterval 類似,這裡不展開細說)。
function useRafInterval( fn: () => void, delay: number | undefined, options?: { immediate?: boolean; }, ) { const immediate = options?.immediate; const fnRef = useLatest(fn); useEffect(() => { // 省略部分程式碼... const timer = setRafInterval(() => { fnRef.current(); }, delay); return () => { clearRafInterval(timer); }; }, [delay]); }
可以看到,跟前面的 useInterval 大部分程式碼邏輯都是一樣的,只是定時使用了 setRafInterval
方法,清除定時器用了 clearRafInterval
。
直接上程式碼:
const setRafInterval = function (callback: () => void, delay: number = 0): Handle { if (typeof requestAnimationFrame === typeof undefined) { // 如果不支援,還是使用 setInterval return { id: setInterval(callback, delay), }; } // 開始時間 let start = new Date().getTime(); const handle: Handle = { id: 0, }; const loop = () => { const current = new Date().getTime(); // 當前時間 - 開始時間,大於設定的間隔,則執行,並重置開始時間 if (current - start >= delay) { callback(); start = new Date().getTime(); } handle.id = requestAnimationFrame(loop); }; handle.id = requestAnimationFrame(loop); return handle; };
首先是用 typeof 判斷進行相容邏輯處理,假如不相容,則兜底使用 setInterval。
初始記錄一個 start 的時間。
在 requestAnimationFrame 回撥中,判斷現在的時間減去開始時間有沒有達到間隔,假如達到則執行我們的 callback 函數。更新開始時間。
清除定時器。
function cancelAnimationFrameIsNotDefined(t: any): t is NodeJS.Timer { return typeof cancelAnimationFrame === typeof undefined; } // 清除定時器 const clearRafInterval = function (handle: Handle) { if (cancelAnimationFrameIsNotDefined(handle.id)) { return clearInterval(handle.id); } cancelAnimationFrame(handle.id); };
假如不支援 cancelAnimationFrame
API,則通過 clearInterval 清除,支援則直接使用 cancelAnimationFrame 清除。
關於定時器,我們平時用得不少,但經常有同學容易忘記清除定時器,結合 useEffect
返回清除副作用函數這個特性,我們可以將這類邏輯一起封裝到 hook 中,讓開發者使用更加方便。
另外,假如希望在頁面不可見的時候,不執行定時器,可以選擇 useRafInterval 和 useRafTimeout,其內部是使用 requestAnimationFrame
進行實現。
以上就是定時器在頁面最小化時不執行實現範例的詳細內容,更多關於定時器頁面最小化不執行的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45