您好,登錄后才能下訂單哦!
這篇文章主要講解了“javascript定時器在頁面最小化時不執行怎么實現”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“javascript定時器在頁面最小化時不執行怎么實現”吧!
看名稱,我們就能大概知道,它們的功能對應的是 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 的區別如下:
可以支持第三個參數,通過 immediate 能夠立即執行我們的定時器。
在變更 delay 的時候,會自動清除舊的定時器,并同時啟動新的定時器。
通過 useEffect 的返回清除機制,開發者不需要關注清除定時器的邏輯,避免內存泄露問題。這點是很多開發者會忽略的點。
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 清除。
感謝各位的閱讀,以上就是“javascript定時器在頁面最小化時不執行怎么實現”的內容了,經過本文的學習后,相信大家對javascript定時器在頁面最小化時不執行怎么實現這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。