Scheduler: postTask() 方法
注意:此功能在 Web Workers 中可用。
Scheduler
接口的 postTask()
方法用于根据 优先级 来 调度 任务。
该方法允许用户选择性地指定任务的最小延迟运行时间、任务优先级以及可用于修改任务优先级和/或中止任务的信号。它返回一个 Promise,该 Promise 会在任务回调函数执行完毕后解析(返回其结果),或在任务被中止或抛出错误时被拒绝。
任务优先级可以是 可变的或不可变的。如果任务优先级永远不需要更改,则应使用 options.priority
参数进行设置(此时通过信号设置的任何优先级都将被忽略)。您仍然可以将 AbortSignal
(无优先级)或 TaskSignal
传递给 options.signal
参数来中止任务。
如果任务优先级可能需要更改,则不得设置 options.priority
参数。相反,应该创建一个 TaskController
,并将其 TaskSignal
传递给 options.signal
。任务优先级将从信号优先级初始化,之后可以使用信号关联的 TaskController
进行修改。
如果未设置优先级,则任务优先级默认为 "user-visible"
。
如果指定了延迟并且大于 0,则任务的执行将被延迟至少这么多毫秒。否则,任务将被立即调度进行优先级排序。
语法
postTask(callback)
postTask(callback, options)
参数
回调
-
一个实现任务的回调函数。回调函数的返回值用于解析此函数返回的 Promise。
options
可选-
任务选项,包括:
priority
可选-
任务的不可变 优先级。可能的值为:
"user-blocking"
、"user-visible"
、"background"
。如果设置了此参数,则在任务的整个生命周期内将使用此优先级,并且signal
上设置的优先级将被忽略。 signal
可选-
一个
TaskSignal
或AbortSignal
,可用于中止任务(通过其关联的控制器)。如果设置了
options.priority
参数,则任务优先级无法更改,并且将忽略信号上的任何优先级。否则,如果信号是TaskSignal
,则其优先级用于设置初始任务优先级,并且信号的控制器之后可以使用它来更改任务优先级。 delay
可选-
任务将被添加到调度器队列的最小时间(以整数毫秒为单位)。实际延迟可能高于指定值,但不会低于。默认延迟为 0。
返回值
返回一个 Promise
,该 Promise 会使用 callback
函数的返回值进行解析,或者可能使用 signal
的中止原因(AbortSignal.reason
)进行拒绝。在回调执行期间抛出的错误也可能导致 Promise 被拒绝。
示例
以下示例是 Prioritized Task Scheduling API > 示例 中提供的实时示例的简化版本。
功能检测
通过在全局作用域(例如,窗口作用域中的 Window.scheduler
或工作线程作用域中的 WorkerGlobalScope.scheduler
)中测试 scheduler
属性,来检查是否支持优先级任务调度。
例如,下面的代码如果在浏览器中支持该 API,则会输出 "Feature: Supported"。
// Check that feature is supported
if ("scheduler" in globalThis) {
console.log("Feature: Supported");
} else {
console.error("Feature: NOT Supported");
}
基本用法
任务被发布,在第一个参数中指定回调函数(任务),在可选的第二个参数中指定任务优先级、信号和/或延迟。该方法返回一个 Promise
,该 Promise 在回调函数执行完毕后解析,或因中止错误或函数中抛出的错误而被拒绝。
由于它返回一个 Promise,因此 postTask()
可以 与链式 Promise 一起使用。下面我们展示如何使用 then
等待 Promise 解析,或使用 catch
等待 Promise 被拒绝。未指定优先级,因此将使用默认优先级 user-visible
。
// 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
该方法也可以在 async function 中与 await
一起使用。下面的代码显示了如何使用此方法等待一个 user-blocking
任务。
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
参数设置 任务优先级。以这种方式设置的优先级无法更改(是 不可变的)。
下面我们发布两组共三项任务,每组任务按优先级倒序排列。最后一项任务具有默认优先级。运行时,每项任务都会简单地记录其预期顺序(我们不需要等待结果,因为要显示执行顺序,无需等待)。
// three tasks, in reverse order of priority
scheduler.postTask(() => console.log("bkg 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("bkg 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) bkg 1 bkg 2
更改任务优先级
任务优先级 也可以通过传递给 postTask()
的可选第二个参数中的 TaskSignal
来获取初始值。如果以此方式设置,则可以使用与信号关联的控制器 随后更改 任务优先级。
注意: 仅当 postTask()
的 options.priority
参数未设置,并且 options.signal
是 TaskSignal
(而不是 AbortSignal
)时,使用信号设置和更改任务优先级才有效。
下面的代码首先展示了如何创建 TaskController
,并在其 TaskController()
构造函数 中将其信号的初始优先级设置为 user-blocking
。
然后,我们使用 addEventListener()
为控制器的信号添加事件监听器(我们也可以使用 TaskSignal.onprioritychange
属性来添加事件处理程序)。事件处理程序使用事件上的 previousPriority
来获取原始优先级,并使用事件目标上的 TaskSignal.priority
来获取新/当前优先级。
// 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
。
// 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");
预期输出如下所示。请注意,在这种情况下,优先级在任务执行之前被更改,但它也可以在任务运行时被更改。
// Expected output
// Priority changed from user-blocking to background.
// Task 1
中止任务
可以使用 TaskController
和 AbortController
以完全相同的方式中止任务。唯一的区别是,如果您还想设置任务优先级,则必须使用 TaskController
。
下面的代码创建一个控制器,并将其信号传递给任务。然后任务立即被中止。这会导致 Promise 被 AbortError
拒绝,该错误在 catch
块中被捕获并记录。请注意,我们也可以侦听 TaskSignal
或 AbortSignal
上触发的 abort
事件,并在那里记录中止。
// 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
是任务添加到调度器之前的最短时间;实际时间可能会更长。
下面的代码显示了添加的两个任务(作为箭头函数),它们都带有延迟。
// 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 |
浏览器兼容性
加载中…