温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

javascript定时器在页面最小化时不执行怎么实现

发布时间:2022-07-13 10:42:25 来源:亿速云 阅读:602 作者:iii 栏目:开发技术

这篇文章主要讲解了“javascript定时器在页面最小化时不执行怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“javascript定时器在页面最小化时不执行怎么实现”吧!

    useInterval 和 useTimeout

    看名称,我们就能大概知道,它们的功能对应的是 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 和 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。(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

    setRafInterval

    直接上代码:

    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 函数。更新开始时间。

    clearRafInterval

    清除定时器。

    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定时器在页面最小化时不执行怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI