{"id":370,"date":"2022-06-02T11:23:52","date_gmt":"2022-06-02T18:23:52","guid":{"rendered":"https:\/\/blog.mozilla.org\/performance\/?p=370"},"modified":"2022-06-02T11:25:52","modified_gmt":"2022-06-02T18:25:52","slug":"prioritized-task-scheduling-api-is-prototyped-in-nightly","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/performance\/2022\/06\/02\/prioritized-task-scheduling-api-is-prototyped-in-nightly\/","title":{"rendered":"Prioritized Task Scheduling API is Prototyped in Nightly"},"content":{"rendered":"<p>In <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1734997\">bug 1734997<\/a>, we prototyped the <a href=\"https:\/\/wicg.github.io\/scheduling-apis\/\">Prioritized Task Scheduling API<\/a>. Having the API prototyped empowers us to experiment with the benefits of this API. It is enabled by default in Nightly at the moment.<\/p>\n<h2>Motivation<\/h2>\n<p>Prioritized Task Scheduling API allows web developers to control and schedule prioritized tasks in a united and flexible way. We believe this API is going to benefit the web because firstly it has valid use cases as large web frameworks (eg. React has attempted to implement a<a href=\"https:\/\/github.com\/facebook\/react\/tree\/main\/packages\/scheduler\"> custom version<\/a> of it before the spec is standardized). Secondly, the current task scheduling primitives (eg. <code>setTimeout<\/code> and <code>requestIdleCallback<\/code>) are inadequate. We think this API is going to provide a more robust solution for scheduling tasks.<\/p>\n<h2>All About the API<\/h2>\n<p>The <code>scheduler<\/code> interface is the centralized controller for this API which lives in every window and worker scope. The <code>scheduler<\/code> interface provides the <code>postTask<\/code> function that allows us to post tasks with not only different priorities but <code>AbortSignal<\/code> to allow us to cancel tasks when they are not needed.<\/p>\n<p>Let\u2019s look at some usage of this API. To <b>post a task<\/b>, we can do something like:<\/p>\n<table>\n<tbody>\n<tr>\n<td><code>function task() {}<\/code><br \/>\n<code>scheduler.postTask(task); \/\/ post a task with `user-visible` priority<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Prioritized Task Scheduling API provides 3 levels of <b>priorities<\/b>, they are<\/p>\n<ul>\n<li aria-level=\"1\">user-blocking<\/li>\n<li aria-level=\"1\">user-visible<\/li>\n<li aria-level=\"1\">background<\/li>\n<\/ul>\n<p>user-blocking is the highest priority, user-visible is the second-highest priority and background is the lowest priority. Each task has a priority associated and user-visible is the default priority.<\/p>\n<p>To post a task with <b>different priorities<\/b>, we can do something like<\/p>\n<table>\n<tbody>\n<tr>\n<td>function task() {}<br \/>\nawait scheduler.postTask(task, {priority: &#8216;user-blocking&#8217;}); const promise = scheduler.postTask(task, {priority: &#8216;background&#8217;});<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><code>postTask<\/code> function also allows us to <b>delay<\/b> the running of a task for x milliseconds. Sample usage of that is<\/p>\n<table>\n<tbody>\n<tr>\n<td><code>scheduler.postTask(task, {delay: 100}); \/\/ delay the running of the task for 100 milliseconds<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Another key concept in <code>postTask<\/code> is <code>AbortSignal<\/code>. When using the <code>postTask<\/code> function, we can pass an <code>AbortSignal<\/code> instance to allow us <b>to cancel the task<\/b> after the task is posted.<\/p>\n<p>To pass an <code>AbortSignal<\/code> and cancel the task afterwards, we could do it as<\/p>\n<table>\n<tbody>\n<tr>\n<td><code>function task() {}<\/code><br \/>\n<code>const aboutController = new AbortController(); \/\/ AbortSignal is created via AbortContoller<\/code><br \/>\n<code>const promise = scheduler.postTask(task, {signal: aboutController.signal});<\/code><br \/>\n<code>aboutController.abort();<\/code><br \/>\n<code>\/\/ promise is rejected<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>In addition to canceling the task, we could also pass a <code>TaskSignal<\/code> to <b>change the priority<\/b> afterwards. This can be done as<\/p>\n<table>\n<tbody>\n<tr>\n<td><code>function task() {}<\/code><br \/>\n<code>const taskController = new TaskController({priority: 'background'}); \/\/ TaskSignal is created via TaskControllerconst promise = scheduler.postTask(task, {signal: taskController.signal});<\/code><br \/>\n<code>\/\/ TaskController inherits AbortController, so taskContoller.abort() also can be used to cancel the task<\/code><code>taskController.setPriority(\"user-blocking\");<\/code><br \/>\n<code>\/\/ A prioritychange event is fired on taskController.signal<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Again, this API is behind the <i>dom.enable_web_task_scheduling<\/i> pref and has only been enabled by default in Nightly since Firefox 101.<\/p>\n<h2>What\u2019s Next?<\/h2>\n<p>So far we\u2019ve learnt that Airbnb has been <a href=\"https:\/\/medium.com\/airbnb-engineering\/building-a-faster-web-experience-with-the-posttask-scheduler-276b83454e91\">using this API with success stories<\/a>. We will continue to learn and experiment how this API is used in the wild and make decisions based on our learnings. Thanks for your reading and please stay tuned for our future Performance API updates.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In bug 1734997, we prototyped the Prioritized Task Scheduling API. Having the API prototyped empowers us to experiment with the benefits of this API. It is enabled by default in &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/performance\/2022\/06\/02\/prioritized-task-scheduling-api-is-prototyped-in-nightly\/\">Read more<\/a><\/p>\n","protected":false},"author":1902,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/posts\/370"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/users\/1902"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/comments?post=370"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/posts\/370\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/media?parent=370"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/categories?post=370"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/performance\/wp-json\/wp\/v2\/tags?post=370"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}