成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何讓定時(shí)器在頁(yè)面最小化的時(shí)候不執(zhí)行?

開(kāi)發(fā) 前端
setTimeout 和 setInterval 作為事件循環(huán)中宏任務(wù)的“兩大主力”,它的執(zhí)行時(shí)機(jī)不能跟我們預(yù)期一樣準(zhǔn)確的,它需要等待前面任務(wù)的執(zhí)行。

注:本系列對(duì) ahooks 的源碼解析是基于 v3.3.13。自己 folk 了一份源碼,主要是對(duì)源碼做了一些解讀,可見(jiàn) 詳情[1]。

今天我們來(lái)聊聊定時(shí)器。

useInterval 和 useTimeout

看名稱,我們就能大概知道,它們的功能對(duì)應(yīng)的是 setInterval 和 setTimeout,那對(duì)比后者有什么優(yōu)勢(shì)?

先看 useInterval,代碼簡(jiǎn)單,如下所示:

function useInterval(
fn: () => void,
delay: number | undefined,
options?: {
immediate?: boolean;
},
) {
const immediate = options?.immediate;
const fnRef = useLatest(fn);
useEffect(() => {
// 忽略部分代碼...
// 立即執(zhí)行
if (immediate) {
fnRef.current();
}
const timer = setInterval(() => {
fnRef.current();
}, delay);
// 清除定時(shí)器
return () => {
clearInterval(timer);
};
// 動(dòng)態(tài)修改 delay 以實(shí)現(xiàn)定時(shí)器間隔變化與暫停。
}, [delay]);
}

跟 setInterval 的區(qū)別如下:

  • 可以支持第三個(gè)參數(shù),通過(guò) immediate 能夠立即執(zhí)行我們的定時(shí)器。
  • 在變更 delay 的時(shí)候,會(huì)自動(dòng)清除舊的定時(shí)器,并同時(shí)啟動(dòng)新的定時(shí)器。
  • 通過(guò) useEffect 的返回清除機(jī)制,開(kāi)發(fā)者不需要關(guān)注清除定時(shí)器的邏輯,避免內(nèi)存泄露問(wèn)題。這點(diǎn)是很多開(kāi)發(fā)者會(huì)忽略的點(diǎn)。

useTimeout 跟上面很類似,如下所示,不再做額外解釋:

function useTimeout(fn: () => void, delay: number | undefined): void {
const fnRef = useLatest(fn);

useEffect(() => {
// ...忽略部分代碼
const timer = setTimeout(() => {
fnRef.current();
}, delay);
return () => {
clearTimeout(timer);
};
// 動(dòng)態(tài)修改 delay 以實(shí)現(xiàn)定時(shí)器間隔變化與暫停。
}, [delay]);
}

setTimeout 和 setInterval 的問(wèn)題

首先,setTimeout 和 setInterval 作為事件循環(huán)中宏任務(wù)的“兩大主力”,它的執(zhí)行時(shí)機(jī)不能跟我們預(yù)期一樣準(zhǔn)確的,它需要等待前面任務(wù)的執(zhí)行。比如下面的 setTimeout 的第二個(gè)參數(shù)設(shè)置為 0,并不會(huì)立即執(zhí)行。

setTimeout(() => {
console.log('test');
}, 0)

另外還有一種情況,setTimeout 和 setInterval 在瀏覽器不可見(jiàn)的時(shí)候(比如最小化的時(shí)候),不同的瀏覽器中設(shè)置不同的時(shí)間間隔的時(shí)候,其表現(xiàn)不一樣。根據(jù) 當(dāng)瀏覽器切換到其他標(biāo)簽頁(yè)或者最小化時(shí),你的js定時(shí)器還準(zhǔn)時(shí)嗎?[2] 這篇文章的實(shí)踐結(jié)論如下:

谷歌瀏覽器中,當(dāng)頁(yè)面處于不可見(jiàn)狀態(tài)時(shí),setInterval 的最小間隔時(shí)間會(huì)被限制為 1s。火狐瀏覽器的 setInterval 和谷歌特性一致,但是 ie 瀏覽器沒(méi)有對(duì)不可見(jiàn)狀態(tài)時(shí)的 setInterval 進(jìn)行性能優(yōu)化,不可見(jiàn)前后間隔時(shí)間不變。

在谷歌瀏覽器中,setTimeout在瀏覽器不可見(jiàn)狀態(tài)下間隔低于1s的會(huì)變?yōu)?s,大于等于1s的會(huì)變成N+1s的間隔值。火狐瀏覽器下setTimeout的最小間隔時(shí)間會(huì)變?yōu)?s,大于等于1s的間隔不變。ie瀏覽器在不可見(jiàn)狀態(tài)前后的間隔時(shí)間不變。

這個(gè)結(jié)論,我沒(méi)有驗(yàn)證過(guò),但看起來(lái)差異挺大,其中還提到了另外一個(gè)選擇,就是 requestAnimationFrame。

window.requestAnimationFrame() 告訴瀏覽器——你希望執(zhí)行一個(gè)動(dòng)畫,并且要求瀏覽器在下次重繪之前調(diào)用指定的回調(diào)函數(shù)更新動(dòng)畫。該方法需要傳入一個(gè)回調(diào)函數(shù)作為參數(shù),該回調(diào)函數(shù)會(huì)在瀏覽器下一次重繪之前執(zhí)行

為了提高性能和電池壽命,因此在大多數(shù)瀏覽器里,當(dāng)requestAnimationFrame() 運(yùn)行在后臺(tái)標(biāo)簽頁(yè)或者隱藏的 <iframe> 里時(shí),requestAnimationFrame() 會(huì)被暫停調(diào)用以提升性能和電池壽命。

所以,ahooks 也提供了使用 requestAnimationFrame 進(jìn)行模擬定時(shí)器處理的 hook,我們一起來(lái)看下。

useRafInterval 和 useRafTimeout

直接看 useRafInterval。(useRafTimeout 和 useRafInterval 類似,這里不展開(kāi)細(xì)說(shuō))。

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 大部分代碼邏輯都是一樣的,只是定時(shí)使用了 setRafInterval? 方法,清除定時(shí)器用了 clearRafInterval。

setRafInterval

直接上代碼:

const setRafInterval = function (callback: () => void, delay: number = 0): Handle {
if (typeof requestAnimationFrame === typeof undefined) {
// 如果不支持,還是使用 setInterval
return {
id: setInterval(callback, delay),
};
}
// 開(kāi)始時(shí)間
let start = new Date().getTime();
const handle: Handle = {
id: 0,
};
const loop = () => {
const current = new Date().getTime();
// 當(dāng)前時(shí)間 - 開(kāi)始時(shí)間,大于設(shè)置的間隔,則執(zhí)行,并重置開(kāi)始時(shí)間
if (current - start >= delay) {
callback();
start = new Date().getTime();
}
handle.id = requestAnimationFrame(loop);
};
handle.id = requestAnimationFrame(loop);
return handle;
};

首先是用 typeof 判斷進(jìn)行兼容邏輯處理,假如不兼容,則兜底使用 setInterval。

初始記錄一個(gè) start 的時(shí)間。

在 requestAnimationFrame 回調(diào)中,判斷現(xiàn)在的時(shí)間減去開(kāi)始時(shí)間有沒(méi)有達(dá)到間隔,假如達(dá)到則執(zhí)行我們的 callback 函數(shù)。更新開(kāi)始時(shí)間。

clearRafInterval

清除定時(shí)器。

function cancelAnimationFrameIsNotDefined(t: any): t is NodeJS.Timer {
return typeof cancelAnimationFrame === typeof undefined;
}
// 清除定時(shí)器
const clearRafInterval = function (handle: Handle) {
if (cancelAnimationFrameIsNotDefined(handle.id)) {
return clearInterval(handle.id);
}
cancelAnimationFrame(handle.id);
};

假如不支持 cancelAnimationFrame API,則通過(guò) clearInterval 清除,支持則直接使用 cancelAnimationFrame 清除。

思考與總結(jié)

關(guān)于定時(shí)器,我們平時(shí)用得不少,但經(jīng)常有同學(xué)容易忘記清除定時(shí)器,結(jié)合 useEffect 返回清除副作用函數(shù)這個(gè)特性,我們可以將這類邏輯一起封裝到 hook 中,讓開(kāi)發(fā)者使用更加方便。

另外,假如希望在頁(yè)面不可見(jiàn)的時(shí)候,不執(zhí)行定時(shí)器,可以選擇 useRafInterval 和 useRafTimeout,其內(nèi)部是使用 requestAnimationFrame 進(jìn)行實(shí)現(xiàn)。

參考資料

[1]詳情: https://github.com/GpingFeng/hooks。

[2]當(dāng)瀏覽器切換到其他標(biāo)簽頁(yè)或者最小化時(shí),你的js定時(shí)器還準(zhǔn)時(shí)嗎?: https://juejin.cn/post/6899796711401586695#comment。

責(zé)任編輯:姜華 來(lái)源: 前端雜貨鋪
相關(guān)推薦

2021-04-13 16:00:54

加密貨幣數(shù)據(jù)貨幣

2013-05-31 09:26:11

云宕機(jī)SLA云應(yīng)用彈性

2023-01-10 13:53:21

Linux定時(shí)器

2022-03-28 17:10:18

樹(shù)莓派服務(wù)器舊硬件

2015-09-18 09:23:34

云APIAPI升級(jí)云服務(wù)中斷

2022-06-01 08:00:00

開(kāi)發(fā)成本功能

2009-11-11 10:14:10

linux定時(shí)器操作系統(tǒng)

2010-07-28 15:56:22

FlexTimer定時(shí)

2015-10-29 10:09:57

混合云影子IT SaaS

2018-11-02 08:10:58

Linuxsystemd定時(shí)器

2009-08-14 10:35:25

C#最小化編寫

2009-07-02 17:59:51

2022-11-02 11:40:16

Flowable定時(shí)器流程

2023-10-18 11:01:07

GNOME按鈕

2011-04-13 11:11:36

VC++托盤程序

2011-10-31 10:21:05

2021-08-03 14:33:53

cron定時(shí)器Linux命令

2021-06-28 06:00:11

systemd定時(shí)器系統(tǒng)運(yùn)維

2010-03-17 12:37:51

Python定時(shí)器

2011-02-15 13:50:01

FreeBSDports
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 99视频免费看 | 天天操综合网站 | 欧美高清性xxxxhdvideosex | 欧美日韩亚洲系列 | 亚洲乱码一区二区三区在线观看 | 午夜免费网站 | 婷婷综合久久 | 久久久成人精品 | 精品亚洲一区二区三区 | 操操操日日日 | 亚洲av毛片 | 久久久久久一区 | 韩日av在线 | 亚洲视频第一页 | 成人精品国产一区二区4080 | 成人a免费 | 欧美精品网站 | 久久亚洲一区二区 | 亚洲精品久久久久中文字幕二区 | 日本在线免费看最新的电影 | a级黄色片在线观看 | 国产四区 | 日韩免费av| 国产伦精品一区二区 | 嫩草视频在线看 | 操操网站| 国产激情亚洲 | 日日日视频 | 欧美激情一区二区 | 亚洲日韩中文字幕一区 | 免费成年网站 | 日日干日日射 | h在线免费观看 | 日韩免费av | 亚洲国产一区二区三区四区 | 亚洲欧洲激情 | 中文字幕二区三区 | 成人免费观看男女羞羞视频 | 最新一级毛片 | 国产精品久久在线观看 | 天天操综合网站 |