Scheduler: postTask() 方法

有限可用性

此功能并非基线功能,因为它在一些最广泛使用的浏览器中无法正常工作。

postTask()Scheduler 接口的方法,用于根据 调度 任务的 优先级 添加任务。

此方法允许用户可选地指定任务运行前的最短延迟时间、任务的优先级以及可用于修改任务优先级和/或中止任务的信号。它返回一个 Promise,该 Promise 通过任务回调函数的结果解析,或者通过中止原因或任务中抛出的错误拒绝。

任务优先级可以是 可变或不可变 的。如果任务优先级永远不需要更改,则应使用 options.priority 参数设置(然后将忽略通过信号设置的任何优先级)。您仍然可以将 AbortSignal(没有优先级)或 TaskSignal 传递给 options.signal 参数以中止任务。

如果需要更改任务优先级,则必须不设置 options.priority 参数。相反,应该创建一个 TaskController,并将它的 TaskSignal 传递给 options.signal。任务优先级将从信号优先级初始化,并且稍后可以使用信号关联的 TaskController 修改它。

如果未设置优先级,则任务优先级默认为 "user-visible"

如果指定了延迟且大于 0,则任务的执行将至少延迟这么多毫秒。否则,任务将立即安排进行优先级排序。

语法

js
postTask(callback)
postTask(callback, options)

参数

callback

实现任务的回调函数。回调的返回值用于解析此函数返回的 Promise。

options 可选

任务选项,包括

priority 可选

任务的不可变 优先级。以下之一:"user-blocking""user-visible""background"。如果设置,则此优先级将用于任务的整个生命周期,并且将忽略 signal 上设置的优先级。

signal 可选

一个 TaskSignalAbortSignal,可用于中止任务(来自其关联的控制器)。

如果设置了 options.priority 参数,则无法更改任务优先级,并且将忽略信号上的任何优先级。否则,如果信号是 TaskSignal,则其优先级用于设置初始任务优先级,并且信号的控制器以后可以使用它来更改任务优先级。

delay 可选

将任务添加到调度程序队列后的最短时间(以毫秒为单位)。实际延迟可能高于指定延迟,但不会低于指定延迟。默认延迟为 0。

返回值

返回一个 Promise,该 Promise 通过 callback 函数的返回值解析,或者可能通过 signal 的中止原因(AbortSignal.reason)拒绝。Promise 也可能因回调在执行期间抛出的错误而被拒绝。

示例

以下示例是 优先级任务调度 API > 示例 中提供的实时示例的略微简化版本。

功能检查

通过测试全局“this”中的 scheduler 属性(例如,窗口范围内的 Window.scheduler 或工作线程范围内的 WorkerGlobalScope.scheduler)来检查是否支持优先级任务调度。

例如,如果此浏览器支持该 API,则以下代码将记录“功能:受支持”。

js
// Check that feature is supported
if ("scheduler" in this) {
  console.log("Feature: Supported");
} else {
  console.error("Feature: NOT Supported");
}

基本用法

发布任务时,在第一个参数中指定回调函数(任务),并在可选的第二个参数中指定任务优先级、信号和/或延迟。此方法返回一个 Promise,该 Promise 通过回调函数的返回值解析,或者通过中止错误或函数中抛出的错误拒绝。

由于它返回一个 Promise,因此 postTask() 可以 与其他 Promise 链式调用。下面我们展示了如何使用 then 等待 Promise 解析,或使用 catch 等待 Promise 拒绝。未指定优先级,因此将使用默认优先级 user-visible

js
// A function that defines a task
function myTask() {
  return "Task 1: user-visible";
}

// Post task with default priority: 'user-visible' (no other options)
// When the task resolves, Promise.then() logs the result.
scheduler
  .postTask(myTask, { signal: abortTaskController.signal })
  .then((taskResult) => console.log(`${taskResult}`)) // Log resolved value
  .catch((error) => console.error("Error:", error)); // Log error or abort

此方法也可以与 await 一起在 异步函数 内部使用。以下代码展示了如何使用此方法等待 user-blocking 任务。

js
function myTask2() {
  return "Task 2: user-blocking";
}

async function runTask2() {
  const result = await scheduler.postTask(myTask2, {
    priority: "user-blocking",
  });
  console.log(result); // 'Task 2: user-blocking'.
}
runTask2();

永久优先级

可以使用可选第二个参数中的 priority 参数设置 任务优先级。以这种方式设置的优先级无法更改(是 [不可变的]/en-US/docs/Web/API/Prioritized_Task_Scheduling_API#mutable_and_immutable_task_priority))。

下面我们发布了两组三个任务,每组成员的优先级按相反顺序排列。最后一个任务具有默认优先级。运行时,每个任务都简单地记录其预期顺序(我们没有等待结果,因为我们不需要等待结果就可以显示执行顺序)。

js
// three tasks, in reverse order of priority
scheduler.postTask(() => console.log("bckg 1"), { priority: "background" });
scheduler.postTask(() => console.log("usr-vis 1"), {
  priority: "user-visible",
});
scheduler.postTask(() => console.log("usr-blk 1"), {
  priority: "user-blocking",
});

// three more tasks, in reverse order of priority
scheduler.postTask(() => console.log("bckg 2"), { priority: "background" });
scheduler.postTask(() => console.log("usr-vis 2"), {
  priority: "user-visible",
});
scheduler.postTask(() => console.log("usr-blk 2"), {
  priority: "user-blocking",
});

// Task with default priority: user-visible
scheduler.postTask(() => {
  console.log("usr-vis 3 (default)");
});

预期输出如下所示:任务按优先级顺序执行,然后按声明顺序执行。

usr-blk 1
usr-blk 2
usr-vis 1
usr-vis 2
usr-vis 3 (default)
bckg 1
bckg 2

更改任务优先级

任务优先级 也可以从传递给可选第二个参数中 postTask()TaskSignal 获取其初始值。如果以这种方式设置,则可以使用与信号关联的控制器更改任务的优先级 [可以更改]/en-US/docs/Web/API/Prioritized_Task_Scheduling_API#mutable_and_immutable_task_priority)。

注意:仅当 postTask()options.priority 参数未设置,并且 options.signalTaskSignal(而不是 AbortSignal)时,使用信号设置和更改任务优先级才有效。

以下代码首先展示了如何创建 TaskController,在 TaskController() 构造函数 中将其信号的初始优先级设置为 user-blocking

然后,我们使用 addEventListener() 为控制器的信号添加事件侦听器(我们也可以使用 TaskSignal.onprioritychange 属性添加事件处理程序)。事件处理程序使用事件上的 previousPriority 获取原始优先级,并使用事件目标上的 TaskSignal.priority 获取新/当前优先级。

js
// Create a TaskController, setting its signal priority to 'user-blocking'
const controller = new TaskController({ priority: "user-blocking" });

// Listen for 'prioritychange' events on the controller's signal.
controller.signal.addEventListener("prioritychange", (event) => {
  const previousPriority = event.previousPriority;
  const newPriority = event.target.priority;
  console.log(`Priority changed from ${previousPriority} to ${newPriority}.`);
});

最后,发布任务,传入信号,然后我们通过在控制器上调用 TaskController.setPriority() 立即将优先级更改为 background

js
// Post task using the controller's signal.
// The signal priority sets the initial priority of the task
scheduler.postTask(() => console.log("Task 1"), { signal: controller.signal });

// Change the priority to 'background' using the controller
controller.setPriority("background");

预期输出如下所示。请注意,在这种情况下,优先级在任务执行之前更改,但它也可能在任务运行期间更改。

js
// Expected output
// Priority changed from user-blocking to background.
// Task 1

中止任务

可以使用 TaskControllerAbortController 以完全相同的方式中止任务。唯一的区别是,如果还想要设置任务优先级,则必须使用 TaskController

以下代码创建了一个控制器并将它的信号传递给任务。然后立即中止任务。这会导致 Promise 因 AbortError 而被拒绝,该错误在 catch 块中捕获并记录。请注意,我们还可以侦听 TaskSignalAbortSignal 上触发的 abort 事件 并记录该处的中止。

js
// Declare a TaskController with default priority
const abortTaskController = new TaskController();
// Post task passing the controller's signal
scheduler
  .postTask(() => console.log("Task executing"), {
    signal: abortTaskController.signal,
  })
  .then((taskResult) => console.log(`${taskResult}`)) //This won't run!
  .catch((error) => console.error("Error:", error)); // Log the error

// Abort the task
abortTaskController.abort();

延迟任务

可以通过在 postTask()options.delay 参数中指定毫秒数来延迟任务。这实际上是在超时时将任务添加到优先级队列,就像使用 setTimeout() 创建的一样。delay 是将任务添加到调度程序之前的最短时间;它可能更长。

以下代码展示了两个添加的任务(作为箭头函数),并带有延迟。

js
// Post task as arrow function with delay of 2 seconds
scheduler
  .postTask(() => "Task delayed by 2000ms", { delay: 2000 })
  .then((taskResult) => console.log(`${taskResult}`));
scheduler
  .postTask(() => "Next task should complete in about 2000ms", { delay: 1 })
  .then((taskResult) => console.log(`${taskResult}`));

规范

规范
优先级任务调度
# dom-scheduler-posttask

浏览器兼容性

BCD 表格仅在启用了 JavaScript 的浏览器中加载。