joken-前端工程师

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: :: :: 管理 ::
  404 随笔 :: 39 文章 :: 8 评论 :: 20万 阅读

requestIdleCallback 是一个浏览器提供的 API,用于在主线程空闲时执行低优先级的操作,而不会阻塞主线程的执行。这对于执行一些非紧急的任务(如统计、数据预处理等)非常有用。

以下是 requestIdleCallback 的基本使用方法:

  1. 定义一个回调函数:这个函数将在主线程空闲时执行。
  2. 调用 requestIdleCallback 并传入回调函数:这个方法会返回一个唯一的 ID,用于后续的取消操作。
  3. (可选)使用 cancelIdleCallback 取消回调:如果需要取消已经排期的回调,可以使用这个方法。

示例代码

// 定义一个回调函数
function myIdleTask(deadline) {
    // 检查是否有剩余时间
    while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && tasks.length > 0) {
        doOneTask();
    }

    // 如果还有任务未完成,继续请求空闲时间
    if (tasks.length > 0) {
        requestIdleCallback(myIdleTask);
    }
}

// 调用 requestIdleCallback 并传入回调函数
let idleCallbackId = requestIdleCallback(myIdleTask);

// 取消回调(可选)
cancelIdleCallback(idleCallbackId);

参数说明

  • 回调函数:接受一个 deadline 参数,该参数是一个对象,包含两个属性:

    • timeRemaining():返回当前帧还剩多少时间(毫秒)。
    • didTimeout:一个布尔值,表示是否因为超时执行了回调。
  • options(可选):可以传入一个配置对象,包含一个 timeout 属性,表示回调函数的最大等待时间(毫秒)。如果设置了 timeout,即使主线程没有空闲时间,回调函数也会在超时后执行。

注意事项

  • requestIdleCallback 在某些浏览器中可能不可用,因此建议使用 polyfill 以确保兼容性。
  • 使用 requestIdleCallback 时,不要依赖它来执行关键任务,因为它可能会在主线程非常繁忙时被推迟执行。

Polyfill

如果需要兼容不支持 requestIdleCallback 的浏览器,可以使用以下 polyfill:

if (!window.requestIdleCallback) {
    window.requestIdleCallback = function (callback, options) {
        const { timeout } = options || {};
        const startTime = Date.now();

        return setTimeout(function () {
            callback({
                timeRemaining: function () {
                    return Math.max(0, timeout - (Date.now() - startTime));
                },
                didTimeout: Boolean(timeout) && Date.now() - startTime >= timeout
            });
        }, 1);
    };
}

if (!window.cancelIdleCallback) {
    window.cancelIdleCallback = function (id) {
        clearTimeout(id);
    };
}

通过这种方式,你可以确保 requestIdleCallback 在所有浏览器中都能正常工作。

对于单页引用可能需要手动关闭requestIdleCallback

requestIdleCallback 本身不会自动关闭或取消已经排期的回调。如果你不再需要执行某个回调,或者组件被卸载了,你需要手动取消该回调。这可以通过 cancelIdleCallback 方法来实现。

以下是一个示例,展示了如何在组件卸载时取消 requestIdleCallback

import { onMounted, onUnmounted, ref } from 'vue';

export default {
  setup() {
    const idleCallbackId = ref(null);

    function idleTask(deadline) {
      // 执行一些任务...
      console.log('Executing idle task');

      // 如果需要继续执行任务,可以再次请求空闲时间
      idleCallbackId.value = requestIdleCallback(idleTask);
    }

    onMounted(() => {
      // 组件挂载时请求空闲时间
      idleCallbackId.value = requestIdleCallback(idleTask);
    });

    onUnmounted(() => {
      // 组件卸载时取消空闲回调
      if (idleCallbackId.value !== null) {
        cancelIdleCallback(idleCallbackId.value);
      }
    });

    return {
      idleCallbackId
    };
  }
};

在这个示例中,idleCallbackId 保存了 requestIdleCallback 返回的 ID。当组件卸载时,通过 cancelIdleCallback 取消回调,以防止组件卸载后仍然执行回调函数。

总结

虽然 requestIdleCallback 不会自动关闭,但在某些情况下(如组件卸载、任务完成等),你需要手动取消回调,以避免不必要的执行和可能的内存泄漏。使用 cancelIdleCallback 可以轻松实现这一点。

如果被执行过的requestIdleCallback,不需要手动关闭

requestIdleCallback 的回调函数在执行完毕后,如果没有再次调用 requestIdleCallback 来安排下一次执行,那么它就不需要被关闭。换句话说,当 requestIdleCallback 的回调函数执行完毕后,它自然就结束了,不需要额外的关闭操作。

但是,如果你在回调函数内部再次调用了 requestIdleCallback 来安排下一次执行,那么你需要确保在适当的时候(例如组件卸载或任务完成时)使用 cancelIdleCallback 来取消未来的回调。

示例

以下是一个示例,展示了如何根据任务列表来决定是否需要再次调用 requestIdleCallback

// 定义一个任务列表
const tasks = [
  () => console.log('Task 1 completed'),
  () => console.log('Task 2 completed'),
  () => console.log('Task 3 completed'),
  // 添加更多任务...
];

// 定义一个回调函数,用于在空闲时间执行任务
function idleTask(deadline) {
  // 检查是否有剩余时间
  while ((deadline.timeRemaining() > 0 || deadline.didTimeout) && tasks.length > 0) {
    // 执行任务
    const task = tasks.shift();
    task();
  }

  // 如果还有任务未完成,继续请求空闲时间
  if (tasks.length > 0) {
    requestIdleCallback(idleTask);
  }
}

// 请求空闲时间并传入回调函数
requestIdleCallback(idleTask);

在这个示例中,idleTask 回调函数会在每次执行时检查任务列表。如果任务列表中还有任务,它会再次调用 requestIdleCallback 来安排下一次执行。如果任务列表为空,回调函数自然结束,不需要额外的关闭操作。

总结

  • 不需要关闭:如果 requestIdleCallback 的回调函数执行完毕后没有再次调用 requestIdleCallback,那么它就不需要被关闭。
  • 需要关闭:如果在回调函数内部再次调用了 requestIdleCallback,那么在适当的时候(如组件卸载或任务完成时)需要使用 cancelIdleCallback 来取消未来的回调。
posted on   joken1310  阅读(301)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示