首页 > web前端 > js教程 > 如何在JavaScript中安排背景任务

如何在JavaScript中安排背景任务

William Shakespeare
发布: 2025-02-18 09:04:11
原创
274 人浏览过

How to Schedule Background Tasks in JavaScript

核心要点

  • JavaScript 是一种阻塞式语言,一次只能执行一项任务,这可能导致长时间运行的脚本使浏览器无响应。但是,可以安排不太重要的后台任务运行,而不会直接影响用户体验。
  • requestIdleCallback 是一个 API,允许在浏览器空闲时安排非必要任务,类似于 requestAnimationFrame 的功能。它可以与超时选项一起使用,以确保任务在设定的时间范围内运行,即使浏览器不空闲也是如此。
  • requestIdleCallback 是一项实验性功能,浏览器支持有限,不适用于执行时间不可预测的任务或解决 Promise 的任务。对于不支持的浏览器或需要直接访问 DOM 的任务,可以使用 Web Workers 或 setTimeout 等替代方案。

如果忘记 JavaScript 的其他所有内容,请永远记住这一点:它会阻塞。想象一下,一个神奇的处理精灵让您的浏览器工作。无论是渲染 HTML、响应菜单命令、在屏幕上绘图、处理鼠标点击还是运行 JavaScript 函数,所有这些都由单个精灵处理。像我们大多数人一样,精灵一次只能做一件事情。如果我们向精灵扔很多任务,它们会被添加到一个大的待办事项列表中,并按顺序处理。当精灵遇到脚本标签或必须运行 JavaScript 函数时,其他所有内容都会停止。代码(如果需要)将被下载并在处理进一步事件或渲染之前立即运行。这是必要的,因为您的脚本可以执行任何操作:加载更多代码、删除每个 DOM 元素、重定向到另一个 URL 等。即使有两个或多个精灵,其他精灵也需要在第一个精灵处理您的代码时停止工作。这就是阻塞。这就是长时间运行的脚本导致浏览器无响应的原因。您通常希望 JavaScript 尽快运行,因为代码会初始化窗口小部件和事件处理程序。但是,还有一些不太重要的后台任务不会直接影响用户体验,例如:

  • 记录分析数据
  • 将数据发送到社交网络(或添加 57 个“分享”按钮)
  • 预取内容
  • 预处理或预渲染 HTML

这些不是时间关键型任务,但是为了使页面保持响应速度,它们不应该在用户滚动或与内容交互时运行。一种选择是使用 Web Workers,它可以在单独的线程中并发运行代码。这是预取和处理的一个很好的选择,但您不允许直接访问或更新 DOM。您可以在自己的脚本中避免这种情况,但您无法保证第三方脚本(例如 Google Analytics)永远不需要它。另一种可能性是 setTimeout,例如 setTimeout(doSomething, 1);。浏览器将在其他立即执行的任务完成后执行 doSomething() 函数。实际上,它被放在待办事项列表的底部。不幸的是,无论处理需求如何,该函数都会被调用。

requestIdleCallback

requestIdleCallback 是一个新的 API,旨在在浏览器喘息的那些时刻安排非必要的后台任务。它让人想起 requestAnimationFrame,它会在下一次重绘之前调用一个函数来更新动画。您可以在此处阅读有关 requestAnimationFrame 的更多信息:使用 requestAnimationFrame 进行简单动画

我们可以像这样检测是否支持 requestIdleCallback

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 执行其他操作
  setTimeout(backgroundTask1, 1);
  setTimeout(backgroundTask2, 1);
  setTimeout(backgroundTask3, 1);
}
登录后复制
登录后复制

您还可以使用超时(以毫秒为单位)指定选项对象参数,例如:

requestIdleCallback(backgroundTask, { timeout: 3000 });
登录后复制
登录后复制

这确保您的函数在最初三秒钟内被调用,无论浏览器是否空闲。requestIdleCallback 只调用您的函数一次,并传递一个具有以下属性的截止日期对象:

  • didTimeout — 如果可选超时触发,则设置为 true
  • timeRemaining() — 返回可执行任务的剩余毫秒数的函数

timeRemaining() 将为您的任务分配不超过 50 毫秒的运行时间。它不会停止超过此限制的任务,但最好再次调用 requestIdleCallback 来安排进一步的处理。让我们创建一个简单的示例,它按顺序执行多个任务。任务作为函数引用存储在数组中:

// 要运行的函数数组
var task = [
  background1,
  background2,
  background3
];

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 尽快运行所有任务
  while (task.length) {
    setTimeout(task.shift(), 1);
  }
}

// requestIdleCallback 回调函数
function backgroundTask(deadline) {
  // 如果可能,运行下一个任务
  while (deadline.timeRemaining() > 0 && task.length > 0) {
    task.shift()();
  }

  // 如果需要,安排进一步的任务
  if (task.length > 0) {
    requestIdleCallback(backgroundTask);
  }
}
登录后复制
登录后复制

requestIdleCallback 中不应该执行的操作?

正如 Paul Lewis 在他关于此主题的博客文章中所指出的那样,您在 requestIdleCallback 中执行的工作应该分成小块。它不适用于执行时间不可预测的任何内容(例如操作 DOM,最好使用 requestAnimationFrame 回调来完成)。您还应该注意解决(或拒绝)Promise,因为回调将在空闲回调完成后立即执行,即使没有更多剩余时间也是如此。

requestIdleCallback 浏览器支持

requestIdleCallback 是一项实验性功能,规范仍在不断变化,因此当您遇到 API 更改时不要感到惊讶。它在 Chrome 47 中受支持……这应该在 2015 年底之前可用。Opera 也应该很快获得此功能。Microsoft 和 Mozilla 都正在考虑使用该 API,而且听起来很有希望。苹果公司像往常一样没有消息。如果您想今天尝试一下,最好的办法是使用 Chrome Canary(Chrome 的一个更新版本,测试不如前者完善,但拥有最新的炫酷功能)。Paul Lewis(上面提到)创建了一个简单的 requestIdleCallback shim。这实现了 API 的描述,但它不是可以模拟浏览器空闲检测行为的 polyfill。它采用像上面的示例一样使用 setTimeout 的方法,但如果您想在没有对象检测和代码分叉的情况下使用 API,这是一个不错的选择。虽然今天的支持有限,但 requestIdleCallback 可能是帮助您最大限度地提高网页性能的有趣工具。但您怎么看呢?我很乐意在下面的评论部分听到您的想法。

关于在 JavaScript 中调度后台任务的常见问题解答 (FAQ)

什么是 JavaScript 中的后台任务 API?

JavaScript 中的后台任务 API 是一种强大的工具,允许开发人员安排后台运行的任务,即使主线程空闲也是如此。此 API 特别适用于需要大量计算或网络请求的任务,因为它允许执行这些任务而不会阻塞主线程并可能导致糟糕的用户体验。后台任务 API 是现代浏览器提供的更大 Web API 的一部分,与传统的 setTimeoutsetInterval 方法相比,它提供了一种更高效且更注重性能的处理后台任务的方法。

后台任务 API 与 setTimeoutsetInterval 有何不同?

setTimeoutsetInterval 函数是 JavaScript 中用于安排任务在特定延迟后或以定期间隔运行的传统方法。但是,这些方法有一些限制,尤其是在性能方面。它们在主线程上运行,这意味着如果它们花费太长时间才能完成,它们可能会阻塞其他任务并可能导致糟糕的用户体验。另一方面,后台任务 API 在后台运行任务,与主线程分开。这意味着它可以处理更密集的任务,而不会影响主线程的性能。

我可以在所有浏览器中使用后台任务 API 吗?

后台任务 API 是现代浏览器提供的 Web API 的一个相对较新的补充,因此,它可能并非在所有浏览器中都受支持。在您的项目中计划使用任何 API 时,始终最好检查您计划使用的 API 的当前支持级别。像 Can I Use 这样的网站提供了有关不同浏览器中各种 API 的支持级别的最新信息。

如何使用后台任务 API 安排后台运行的任务?

要使用后台任务 API 安排任务,您可以使用 requestIdleCallback 方法。此方法将回调函数作为其第一个参数,该函数将在浏览器空闲时执行。这是一个基本示例:

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 执行其他操作
  setTimeout(backgroundTask1, 1);
  setTimeout(backgroundTask2, 1);
  setTimeout(backgroundTask3, 1);
}
登录后复制
登录后复制

如何取消已安排的后台任务?

如果您需要取消使用 requestIdleCallback 方法安排的后台任务,可以使用 cancelIdleCallback 方法。此方法将 requestIdleCallback 返回的 ID 作为其参数。这是一个示例:

requestIdleCallback(backgroundTask, { timeout: 3000 });
登录后复制
登录后复制

requestIdleCallback 中的超时选项有什么用?

requestIdleCallback 中的超时选项用于指定浏览器在运行回调之前应等待的最大时间(以毫秒为单位),即使它不空闲也是如此。如果您的后台任务需要在特定时间范围内运行,这将非常有用。

如何处理后台任务中的错误?

处理使用后台任务 API 安排的后台任务中的错误类似于处理任何其他 JavaScript 代码中的错误。您可以使用 try/catch 块来捕获在任务执行期间发生的任何错误。这是一个示例:

// 要运行的函数数组
var task = [
  background1,
  background2,
  background3
];

if ('requestIdleCallback' in window) {
  // requestIdleCallback 受支持
  requestIdleCallback(backgroundTask);
} else {
  // 不支持 - 尽快运行所有任务
  while (task.length) {
    setTimeout(task.shift(), 1);
  }
}

// requestIdleCallback 回调函数
function backgroundTask(deadline) {
  // 如果可能,运行下一个任务
  while (deadline.timeRemaining() > 0 && task.length > 0) {
    task.shift()();
  }

  // 如果需要,安排进一步的任务
  if (task.length > 0) {
    requestIdleCallback(backgroundTask);
  }
}
登录后复制
登录后复制

我可以在 Node.js 中使用后台任务 API 吗?

后台任务 API 是现代浏览器提供的 Web API 的一部分,因此默认情况下它在 Node.js 中不可用。但是,还有其他方法可以在 Node.js 中运行后台任务,例如使用工作线程或子进程。

我可以将后台任务 API 与 Promise 或 async/await 一起使用吗?

后台任务 API 不返回 Promise,因此不能直接与 async/await 一起使用。但是,如果您需要在异步上下文中使用它,则可以将 requestIdleCallback 方法包装在 Promise 中。这是一个示例:

window.requestIdleCallback(() => {
  // 您的后台任务在此处
});
登录后复制

后台任务 API 的一些用例是什么?

后台任务 API 对于任何需要大量计算或网络请求的任务都很有用,因为它允许执行这些任务而不会阻塞主线程。用例的一些示例可能包括从 API 获取和处理数据、执行复杂的计算或根据用户交互更新 UI。

以上是如何在JavaScript中安排背景任务的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板