Intent to Implement: requestIdleCallback

107 views
Skip to first unread message

Ross McIlroy

unread,
Jul 28, 2015, 11:34:23 AM7/28/15
to blink-dev
Contact emails

Spec

Summary
An API which allows posting of tasks which are schedule during periods when the browser is idle, and are passed a deadline, when called, which is calculated based on how long the browser expects to remain idle. This enables developers to perform background work on the main event loop, without impact latency-critical events such as animation and input response.

Motivation
Web pages often want to execute computation tasks on the browser's event loop which are not time-critical, but might take a significant portion of time to perform. Currently these background tasks are typically performed using setTimeout. The disadvantage of this approach is that the browser has no way of knowing whether a given setTimeout callback is time-critical or could be delayed until the browser is otherwise idle. In addition, the browser isn't able to provide the callback with any information about how long it can continue to execute without delaying time-critical operations and causing jank or other user-perceptible delays.

The requestIdleCallback API is intended to mitigate these issues by enabling developers to explicitly mark non-urgent background work as such, and to provide the callback with an estimation of how long the browser expects to remain idle.

The motivation of API came from our work on the Blink Scheduler, where a similar API is provided internally and is used by various components of Blink to schedule background work.

Compatibility Risk
Internet Explorer: Mixed public signals (very interested in providing this capability, but concerned that this might overlap with their setImmediate API)
Safari: No public signals
Web developers: Positive

There is some discussion on the spec as to whether this API should be Promise based instead of callback based. We will not ship this API before this has been decided, but intend to implement support in Chrome for the callback implementation (behind a flag) to allow experimentation.

Developers will be able to detect whether this API is available with simple feature detection (checking if the requestIdleCallback function exists).

Ongoing technical constraints
None

Will this feature be supported on all six Blink platforms (Windows, Mac, Linux,
Chrome OS, Android, and Android WebView)? 
Yes

OWP launch tracking bug

Link to entry on the Chromium Dashboard

Requesting approval to ship?
No

PhistucK

unread,
Jul 28, 2015, 12:05:22 PM7/28/15
to Ross McIlroy, blink-dev
​I think this is a good addition.


On Tue, Jul 28, 2015 at 6:33 PM, Ross McIlroy <rmci...@chromium.org> wrote:
Web developers: Positive

​References (other than my response :))?​



PhistucK

Ross McIlroy

unread,
Jul 28, 2015, 12:18:53 PM7/28/15
to PhistucK, Ross McIlroy, blink-dev
On Tue, Jul 28, 2015 at 6:33 PM, Ross McIlroy <rmci...@chromium.org> wrote:
Web developers: Positive

​References (other than my response :))?​

Yes, there has been interest from Facebook's react team to enable the react framework to incrementally perform expensive UI calculations, such as rendering new content, at the  end of every animation frame in any remaining frame time (link).  

There has also been interest from Google's DevRel team and from some other teams in Google interested in scheduling background work (I have no external references for this though unfortunately).

Cheers,
Ross

Philip Jägenstedt

unread,
Jul 29, 2015, 7:37:34 AM7/29/15
to Ross McIlroy, blink-dev
Sounds pretty great!

I wonder if there may be cases, now or in the near future, where the work performed in the callback can itself change how much time is available, like if it generates enough garbage that a GC becomes a good idea. If so, would IdleDeadline.deadline change during execution?

Also, does IdleDeadline.isExceeded() add any capability, or is it just a convenience?

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

Ross McIlroy

unread,
Jul 29, 2015, 9:40:10 AM7/29/15
to Philip Jägenstedt, Ross McIlroy, blink-dev
On 29 July 2015 at 12:37, Philip Jägenstedt <phi...@opera.com> wrote:
Sounds pretty great!

Neat, glad you like it :).
 
I wonder if there may be cases, now or in the near future, where the work performed in the callback can itself change how much time is available, like if it generates enough garbage that a GC becomes a good idea. If so, would IdleDeadline.deadline change during execution?

Certainly there are situations where the work done during the callback could trigger things to happen which take longer than expected (e.g., inducing a layout, or causing a GC during the callback).  These would happen during the callback itself and would just reduce the amount of work the callback, not the deadline itself, so the callback could compensate assuming it checked isExceeded() often enough. 

For your example of generating garbage - if it generated a lot of garbage it might be a good time to do some GC work, however we are either going to do the GC work during the callback itself (as in the above paragraph), or during idle GC tasks, which are scheduled internally using the same PostIdleTask mechanism as requestIdleCallback (rIC), and so would either get to run in any remaining time after the rIC callback, or would run during the next idle period in a round-robin style interleaved with the rIC callbacks.

As for other kinds of work which could cause the deadline to change, I'm not sure. The inter-frame deadline is currently set by the compositor based on when it expects to start drawing the next frame (synced with v-syncs). I don't think this would need changing even if the DOM was changed by the callback - this might trigger a relayout on the next frame, but so could a rAF (which happens after the deadline). Is there anything else you had in mind?

Also, does IdleDeadline.isExceeded() add any capability, or is it just a convenience?

Currently it's just a convenience, however further down the road it would allow us to signal to the callbacks that other more important work has just come up, even if the deadline hasn't yet passed.

Cheers,
Ross

Justin Novosad

unread,
Jul 29, 2015, 10:45:19 AM7/29/15
to Ross McIlroy, blink-dev
Small question about the spec. There does not seem to be any provision for guaranteeing that the user agent will execute an idle callback. To be more specific, the optional deadline argument does not guarantee that the callback will be executed before the script execution context is destroyed. It would be nice to be able to provide some guarantee of execution. Without that guarantee, one would not want to implement any critical task (like saving user data) using idle callbacks.

Alex Clarke

unread,
Jul 29, 2015, 12:45:24 PM7/29/15
to Justin Novosad, Ross McIlroy, blink-dev
I believe that's on purpose, there may not be any idle time if the thread is very busy.   You could post a idle callback and a setTimeout and use which ever got there first.

Ross McIlroy

unread,
Jul 29, 2015, 1:38:36 PM7/29/15
to Alex Clarke, Justin Novosad, Ross McIlroy, blink-dev

On Wed, Jul 29, 2015 at 3:45 PM, Justin Novosad <ju...@chromium.org> wrote:
Small question about the spec. There does not seem to be any provision for guaranteeing that the user agent will execute an idle callback. To be more specific, the optional deadline argument does not guarantee that the callback will be executed before the script execution context is destroyed. It would be nice to be able to provide some guarantee of execution. Without that guarantee, one would not want to implement any critical task (like saving user data) using idle callbacks.

This is an interesting idea. I guess this would be equivalent to adding an handler to the onunload (or onbeforeunload) event, which is canceled if the callback get's triggered through other means (much like the current optional timer parameter is equivalent to a cancelable setTimeout). You could build this manually, but it might be nice to have it built-in to the API like the timeout parameter.  I've opened https://github.com/w3c/requestidlecallback/issues/3 to discuss adding this to the spec - feel free to chip in on the issue directly.


On 29 July 2015 at 17:45, Alex Clarke <alexc...@google.com> wrote:
I believe that's on purpose, there may not be any idle time if the thread is very busy.   You could post a idle callback and a setTimeout and use which ever got there first.

Actually no - we have added an optional timeout parameter to the requestIdleCallback API which enables users to ensure that a callback happens within a certain time period whether the main thread is busy or not (see section 4). What I believe Justin is asking for is the ability to additional ensure that the callback happens before the page is unloaded (i.e., navigated away), even if there is no idle time and the timeout hasn't yet expired.

Philip Jägenstedt

unread,
Jul 30, 2015, 7:14:00 AM7/30/15
to Ross McIlroy, Ross McIlroy, blink-dev
On Wed, Jul 29, 2015 at 3:39 PM, Ross McIlroy <rmci...@google.com> wrote:
On 29 July 2015 at 12:37, Philip Jägenstedt <phi...@opera.com> wrote:
Sounds pretty great!

Neat, glad you like it :).
 
I wonder if there may be cases, now or in the near future, where the work performed in the callback can itself change how much time is available, like if it generates enough garbage that a GC becomes a good idea. If so, would IdleDeadline.deadline change during execution?

Certainly there are situations where the work done during the callback could trigger things to happen which take longer than expected (e.g., inducing a layout, or causing a GC during the callback).  These would happen during the callback itself and would just reduce the amount of work the callback, not the deadline itself, so the callback could compensate assuming it checked isExceeded() often enough. 

For your example of generating garbage - if it generated a lot of garbage it might be a good time to do some GC work, however we are either going to do the GC work during the callback itself (as in the above paragraph), or during idle GC tasks, which are scheduled internally using the same PostIdleTask mechanism as requestIdleCallback (rIC), and so would either get to run in any remaining time after the rIC callback, or would run during the next idle period in a round-robin style interleaved with the rIC callbacks.

As for other kinds of work which could cause the deadline to change, I'm not sure. The inter-frame deadline is currently set by the compositor based on when it expects to start drawing the next frame (synced with v-syncs). I don't think this would need changing even if the DOM was changed by the callback - this might trigger a relayout on the next frame, but so could a rAF (which happens after the deadline). Is there anything else you had in mind?

Anything that does work synchronously, like a sync GC or a sync layout, is not an issue, as you say.

A need for async GC is the only thing I had considered, but I guess there's very little point in trying to do it before the next animation frame by signaling to the ongoing callback that it should stop.

The only other async thing that comes to mind is style recalc and layout (when the specified style changes), but I'm assuming that's delayed until after animation frame callbacks anyway, and I can't really imagine why you would delay use-visible work like that to an idle callback.

Also, does IdleDeadline.isExceeded() add any capability, or is it just a convenience?

Currently it's just a convenience, however further down the road it would allow us to signal to the callbacks that other more important work has just come up, even if the deadline hasn't yet passed.

Yeah, that sounds like a reasonable escape hatch if it should turn out that the deadline needs to be adjusted during execution.

Philip
Reply all
Reply to author
Forward
0 new messages