成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

演示當(dāng)定時(shí)器在頁(yè)面最小化時(shí)無(wú)法執(zhí)行

3403771864 / 759人閱讀

  我們講述的是關(guān)于 ahooks 源碼系列文章的第七篇,總結(jié)主要講述下面幾點(diǎn):

  鞏固 React hooks 的理解。

  學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫(kù)。

  培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫(kù)是一個(gè)對(duì)源碼閱讀不錯(cuò)的選擇。

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

  現(xiàn)在進(jìn)入主題:定時(shí)器。

  useInterval 和 useTimeout,它們的功能對(duì)應(yīng)的是 setInterval 和 setTimeout,那對(duì)比后者有什么優(yōu)勢(shì)?

  先看useInterval,代碼如下所示:

  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)題。記住這個(gè)點(diǎn)是在開(kāi)發(fā)中很容易忽略的。

  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ī)無(wú)法和我們預(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í)嗎?這篇文章的實(shí)踐結(jié)論如下:

  當(dāng)谷歌瀏覽器中,在頁(yè)面處于不可見(jiàn)狀態(tài)時(shí),setInterval 的最小間隔時(shí)間會(huì)被限制為 1s??稍诨鸷鼮g覽器的 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í)間不變。

  總結(jié)上面看來(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)行兼容邏輯處理,出現(xiàn)兼容,那就需要setInterval出場(chǎng)。

  初始記錄一個(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);
  };

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

  復(fù)盤與總結(jié)

  我們開(kāi)發(fā)者對(duì)于定時(shí)器,要記得及時(shí)清楚,這里建議用seEffect返回清除副作用函數(shù)這個(gè)特性,我們可以將這類邏輯一起封裝到 hook 中,怎么樣是不是很方便。

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

  有關(guān)定時(shí)器在頁(yè)面最小化時(shí)不執(zhí)行實(shí)現(xiàn)示例的詳細(xì)內(nèi)容已敘述完,請(qǐng)大家多多關(guān)注后續(xù)更多精彩內(nèi)容。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/128190.html

相關(guān)文章

  • 《高性能javascript》閱讀摘要

    摘要:當(dāng)執(zhí)行上下文被創(chuàng)建時(shí),它的作用域鏈初始化為當(dāng)前運(yùn)行函數(shù)的屬性中的對(duì)象。該過(guò)程搜索執(zhí)行環(huán)境的作用域鏈,查找同名的標(biāo)識(shí)符。搜索實(shí)例成員比從字面量或局部變量中讀取數(shù)據(jù)代價(jià)更高,再加上遍歷原型鏈帶來(lái)的開(kāi)銷,這讓性能問(wèn)題更為嚴(yán)重。 最近在閱讀這本Nicholas C.Zakas(javascript高級(jí)程序設(shè)計(jì)作者)寫的最佳實(shí)踐、性能優(yōu)化類的書(shū)。記錄下主要知識(shí)。 加載和執(zhí)行 腳本位置 放在中的...

    duan199226 評(píng)論0 收藏0
  • 《高性能javascript》閱讀摘要

    摘要:當(dāng)執(zhí)行上下文被創(chuàng)建時(shí),它的作用域鏈初始化為當(dāng)前運(yùn)行函數(shù)的屬性中的對(duì)象。該過(guò)程搜索執(zhí)行環(huán)境的作用域鏈,查找同名的標(biāo)識(shí)符。搜索實(shí)例成員比從字面量或局部變量中讀取數(shù)據(jù)代價(jià)更高,再加上遍歷原型鏈帶來(lái)的開(kāi)銷,這讓性能問(wèn)題更為嚴(yán)重。 最近在閱讀這本Nicholas C.Zakas(javascript高級(jí)程序設(shè)計(jì)作者)寫的最佳實(shí)踐、性能優(yōu)化類的書(shū)。記錄下主要知識(shí)。 加載和執(zhí)行 腳本位置 放在中的...

    afishhhhh 評(píng)論0 收藏0
  • 瀏覽器知識(shí)

    摘要:瀏覽器的渲染進(jìn)程是多線程的。異步請(qǐng)求線程在在連接后是通過(guò)瀏覽器新開(kāi)一個(gè)線程請(qǐng)求將檢測(cè)到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件隊(duì)列中。 [TOC] 瀏覽器進(jìn)程線程 區(qū)分線程和進(jìn)程 **- 什么是進(jìn)程** 狹義定義:進(jìn)程是正在運(yùn)行的程序的實(shí)例(an instance of a computer program that is being exe...

    Pluser 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<