Scheduler: postTask() method
============================

Limited availability
--------------------

This feature is not Baseline because it does not work in some of the most widely-used browsers.

* Learn more
* See full compatibility
* Report feedback
The **`postTask()`** method of the `Scheduler` interface is used for adding tasks to be scheduled according to their priority.

 The method allows users to optionally specify a minimum delay before the task will run, a priority for the task, and a signal that can be used to modify the task priority and/or abort the task.
 It returns a promise that is resolved with the result of the task callback function, or rejected with the abort reason or an error thrown in the task.

 Task priority can be mutable or immutable.
 If the task priority will never need to change then it should be set using the `options.priority` parameter (any priority set through a signal will then be ignored).
 You can still pass an `AbortSignal` (which has no priority) or `TaskSignal` to the `options.signal` parameter for aborting the task.

 If the task priority might need to be changed the `options.priority` parameter must not be set.
 Instead a `TaskController` should be created and its `TaskSignal` should be passed to `options.signal`.
 The task priority will be initialized from the signal priority, and can later be modified using the signal's associated `TaskController`.

If no priority is set then the task priority defaults to `"user-visible"`.

 If a delay is specified and greater than 0, then the execution of the task will be delayed for at least that many milliseconds.
 Otherwise the task is immediately scheduled for prioritization.

Syntax
------


```js
postTask(callback)
postTask(callback, options)
```

### Parameters

`callback`

 An callback function that implements the task.
 The return value of the callback is used to resolve the promise returned by this function.


`options` Optional

Task options, including:

`priority` Optional

 The immutable priority of the task.
 One of: `"user-blocking"`, `"user-visible"`, `"background"`.
 If set, this priority is used for the lifetime of the task and priority set on the `signal` is ignored.


`signal` Optional

A `TaskSignal` or `AbortSignal` that can be used to abort the task (from its associated controller).

 If the `options.priority` parameter is set then the task priority cannot be changed, and any priority on the signal is ignored.
 Otherwise, if the signal is a `TaskSignal` its priority is used to set the initial task priority, and the signal's controller may later use it to change the task priority.


`delay` Optional

 The minimum amount of time after which the task will be added to the scheduler queue, in whole milliseconds.
 The actual delay may be higher than specified, but will not be less.
 The default delay is 0.



### Return Value

 Returns a `Promise` that is resolved with the return value of the `callback` function, or which may be rejected with the `signal`'s abort reason (`AbortSignal.reason`).
 The promise may also be rejected with an error thrown by the callback during execution.

Examples
--------

The following examples are slightly simplified versions of the live examples provided in Prioritized Task Scheduling API > Examples.

### Feature checking

Check whether prioritized task scheduling is supported by testing for the `scheduler` property in the global "`this`" (such as `Window.scheduler`).

For example, the code below logs "Feature: Supported" if the API is supported on this browser.


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

### Basic usage

 Tasks are posted specifying a callback function (task) in the first argument, and an optional second argument that can be used to specify a task priority, signal, and/or delay.
 The method returns a `Promise` that resolves with the return value of the callback function, or rejects with either an abort error or an error thrown in the function.

 Because it returns a promise, `postTask()` can be chained with other promises.
 Below we show how to wait on the promise to resolve using `then` or reject using `catch`.
 The priority is not specified, so the default priority of `user-visible` will be used.


```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
```


 The method can also be used with `await` inside an async function.
 The code below shows how you might use this approach to wait on a `user-blocking` task.


```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();
```

### Permanent priorities

Task priorities may be set using `priority` parameter in the optional second argument.
 Priorities that are set in this way cannot be changed (are immutable).

 Below we post two groups of three tasks, each member in reverse order of priority.
 The final task has the default priority.
 When run, each task simply logs it's expected order (we're not waiting on the result because we don't need to in order to show execution order).


```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)");
});
```


The expected output is shown below: tasks are executed in priority order, and then declaration order.
```

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

### Changing task priorities

Task priorities can also take their initial value from a `TaskSignal` passed to `postTask()` in the optional second argument.
 If set in this way, the priority of the task can then be changed using the controller associated with the signal.

**Note:** Setting and changing task priorities using a signal only works when the `options.priority` argument to `postTask()` is not set, and when the `options.signal` is a `TaskSignal` (and not an `AbortSignal`).

The code below first shows how to create a `TaskController`, setting the initial priority of its signal to `user-blocking` in the `TaskController()` constructor.

 We then use `addEventListener()` to add an event listener to the controller's signal (we could alternatively use the `TaskSignal.onprioritychange` property to add an event handler).
 The event handler uses `previousPriority` on the event to get the original priority and `TaskSignal.priority` on the event target to get the new/current 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}.`);
});
```


Finally, the task is posted, passing in the signal, and then we immediately change the priority to `background` by calling `TaskController.setPriority()` on the controller.


```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");
```


 The expected output is shown below.
 Note that in this case the priority is changed before the task is executed, but it could equally have been changed while the task was running.


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

### Aborting tasks

 Tasks can be aborted using either `TaskController` and `AbortController`, in exactly the same way.
 The only difference is that you must use `TaskController` if you also want to set the task priority.

 The code below creates a controller and passes its signal to the task.
 The task is then immediately aborted.
 This causes the promise to be rejected with an `AbortError`, which is caught in the `catch` block and logged.
 Note that we could also have listened for the `abort` event fired on the `TaskSignal` or `AbortSignal` and logged the abort there.


```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();
```

### Delaying tasks

 Tasks can be delayed by specifying an integer number of milliseconds in the `options.delay` parameter to `postTask()`.
 This effectively adds the task to the prioritized queue on a timeout, as might be created using `setTimeout()`.
 The `delay` is the minimum amount of time before the task is added to the scheduler; it may be longer.

The code below shows two tasks added (as arrow functions) with a 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}`));
```

Specifications
--------------

| Specification |
| --- |
| Prioritized Task Scheduling # dom-scheduler-posttask |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.