A Faster Web

Making the Most of Idle Moments with requestIdleCallback()

by Shawn Maust • 20 November 2017

When executing scripts on a page, one thing we want to avoid is creating unnecessary jank for the user. This particularly true when we’re doing a lower priority task that doesn’t have to be called that exact moment. In those cases, it would be helpful to be able to delay those calls until we’re sure the browser isn’t working on something more important.

With requestIdleCallback() , an API available in many current browsers, we can do just that: delay execution of scripts until the browser has enough time to run them smoothly. From the MDN docs:

“Window.requestIdleCallback() makes it possible to become actively engaged in helping to ensure that the browser’s event loop runs smoothly, by allowing the browser to tell your code how much time it can safely use without causing the system to lag…” ( Source )

This effectively allows us to register a callback function to be executed when the browser is idle . Instead of us trying to calculate when to run certain tasks, we can simply tell the browser to run them whenever it gets a chance. That way, they’ll get done, but they won’t get called at the exact moment the browser is busy handling some other user interaction or event.

Usage and Syntax

Scheduling the callback.

The syntax to schedule a callback during an idle period is:

The first argument is the callback function we want executed when the browser is idle next. The second argument is an object we can pass in additional options with. Current the only option for this object is setting a timeout . This allows us to specify the maximum amount of time we’re willing to wait before the browser must execute the callback.

For instance, if I wanted to call a function that will process some lower priority tasks, but I also want to ensure that it gets run within the next 3 seconds, I could do this:

This would add a call to my doLowPriorityTask() function into the queue of things to do whenever the browser is idle. But if that doesn’t happen in the next 3 seconds, the function would be called regardless.

Note: Calling requestIdleCallback() will return an ID which can be used to later cancel the callback.

Canceling the Callback

In those situations where you need to cancel a previously scheduled callback, you can do so by using:

The handle is the ID value returned when initially scheduling the callback.

The Callback Itself

When the callback is called, it will be passed an IdleDeadline object. This object contains a didTimeout property and a timeRemaining() method.

didTimeout : A Boolean that tells us whether the callback was executed because it hit the specified timeout.

timeRemaining() : Provide an estimate of the number of milliseconds remaining in the current idle period. If it’s over, the value will be 0.

This allows us to check how much time is left, or whether we hit a timeout. With this information, we can decide how we want to proceed within the callback. For some tasks, we may want to ensure that we have a certain minimum amount of time remaining in the idle period. Or we may want to handle a task differently if it’s hit the timeout.

requestIdleCallback() is currently supported by Chrome, Firefox, Opera, and Android . MS Edge and Safari are still under consideration. For the browsers that do not support it, there is a standard fallback that can be used:

Best Practices

When scheduling tasks using requestIdleCallback() , there are a few best practices to keep in mind.

Use it for lower priority tasks . This may be obvious, but if you choose to wait until the system’s idle to execute a task, you’re losing control of when that task will be called. Which means you won’t want to do this for critical tasks that need to be done immediately.

But if it’s something that can afford a little delay, like sending various analytics information, allowing the browser to fit it in whenever it gets a moment makes sense.

Refrain from changing the DOM . Since the idle time will come at the end of the frame, all the layout changes will have already been made by the time the callback is called. Making further changes to the DOM will force the browser to stop and redo its layout calculations. If there are changes to the DOM, it’s better to use requestAnimationFrame() to make those changes.

One pattern to do this is to use a documentFragment ( document.createDocumentFragment() ) to store pending changes made in the scheduled task, and then use requestAnimationFrame() to add this fragment to the DOM.

Stay away from tasks which could take an unpredictable amount of time. A good example would be resolving or rejecting Promises. Doing so would invoke the handler for that promise’s resolution or rejection as soon as your callback returns, which may or may not be a good time for it to be invoked.

Use timeouts only when needed . Timeouts allow you to ensure the task gets run at a specific time, but depending on what else the browser is trying to do at that moment, this may also cause some performance issues if there are lots of other things going on.

Mozilla has a good example that shows how all these various pieces can work together: https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API#Example

  • Cooperative Scheduling of Background Tasks , W3C Editor’s draft
  • window.requestIdleCallback() , MDN web docs
  • window.cancelIdleCallback() , MDN web docs
  • IdleDeadline interface , MDN web docs
  • Cooperative Scheduling of Background Tasks API (Example) , MDN Web docs
  • Using requestIdleCallback , by Paul Lewis

@ncjamieson

Rxjs: how to use request​idle​callback.

June 26, 2020  •  4 minute read

At least three times in the last few weeks, I’ve been asked about whether or not it would be possible — or whether there are plans — to write a scheduler that’s based on requestIdleCallback , so I figured I ought to write a blog article about it.

The MDN documentation for requestIdleCallback has — at the top of the page — this warning:

This is an experimental technology. Check the Browser compatibility table carefully before using this in production.

The compatibility table in the MDN documentation — and on caniuse.com , too — shows that requestIdleCallback is not supported on Safari or iOS Safari. The table includes a link to the draft specification  — dated 30 December 2019.

From that, the second part of the question can be answered: no, there is no chance that support for requestIdleCallback will be added to the RxJS core until the feature is widely supported. Adding support for a feature that’s unavailable on both Safari and iOS Safari is not something that I would favour and I would expect it would be something that other core team members would be unlikely to entertain.

The first part of the question is a little more interesting.

I think it’s not so much a question of whether a scheduler based on requestIdleCallback could be written. Rather, it’s should such a scheduler be written?

I think the answer is no .

How would it work?

If a scheduler based on requestIdleCallback were to be written, how would it work?

In the RxJS core, the queueScheduler and asapScheduler implementations fall back to the asyncScheduler whenever a duration is specified. This makes sense, as both the queueScheduler and asapScheduler are ‘faster’ than the asyncScheduler  — the former is synchronous and the latter is a micro task, whereas the asyncScheduler is a macro task.

It makes less sense for an idle scheduler.

If an idle scheduler where to be called with a duration of zero, its scheduled action might not be executed for a considerable period of time — i.e. not until the browser is idle. However, if it were called with a duration of one millisecond, falling back to the asyncScheduler would schedule the action for execution for the next millisecond — regardless of whether the browser is idle at that time or not.

Falling back from the animationFrameScheduler to the asyncScheduler is arguably weird behaviour, too. Which is one of the reasons there is now an animationFrames observable in the version 7 beta of RxJS.

There is also the question of what an idle scheduler should do if an action is scheduled when an action is already pending — i.e. when the scheduler is waiting for the browser to become idle so that an already scheduled action can be executed. Should it execute both actions when the browser becomes idle? Should it execute one action and the wait for the browser to again become idle before executing the second?

Using an idle observable instead

Given that it’s questionable to fallback to the asyncScheduler and that it’s not clear how an idle scheduler should schedule its actions, let’s look at whether or not an idle observable could be used instead.

Let’s implement an idle observable like this:

Unlike the animationFrames observable, our idle observable emits only once — when the browser becomes idle — and then completes. It does this so that it doesn’t continuously emit notifications whenever the browser happens to be idle.

Let’s see how we could compose observables using idle .

If we have a source that emits values upon which some work needs to performed, we can to this:

Here, the work will be performed whenever the source emits a next notification.

If we want to wait until the browser is idle before performing the work, we can use the idle observable, like this:

Here, our composed observable will wait until the browser is idle before performing the work on each buffered value.

If we want to perform the work on only a single value each time the browser becomes idle, we could do this:

Here, the composed observable will perform the work on one value and will then wait until the browser again becomes idle before performing the next.

To me, this seems pretty flexible, so this is the approach that I’d be inclined to take when/if requestIdleCallback becomes more widely supported.

  • Español – América Latina
  • Português – Brasil
  • Tiếng Việt
  • Chrome for Developers

Using requestIdleCallback

Many sites and apps have a lot of scripts to execute. Your JavaScript often needs to be run as soon as possible, but at the same time you don’t want it to get in the user’s way. If you send analytics data when the user is scrolling the page, or you append elements to the DOM while they happen to be tapping on the button, your web app can become unresponsive, resulting in a poor user experience.

Using requestIdleCallback to schedule non-essential work.

The good news is that there’s now an API that can help: requestIdleCallback . In the same way that adopting requestAnimationFrame allowed us to schedule animations properly and maximize our chances of hitting 60fps, requestIdleCallback will schedule work when there is free time at the end of a frame, or when the user is inactive. This means that there’s an opportunity to do your work without getting in the user’s way. It’s available as of Chrome 47, so you can give it a whirl today by using Chrome Canary! It is an experimental feature , and the spec is still in flux, so things could change in the future.

Why should I use requestIdleCallback?

Scheduling non-essential work yourself is very difficult to do. It’s impossible to figure out exactly how much frame time remains because after requestAnimationFrame callbacks execute there are style calculations, layout, paint, and other browser internals that need to run. A home-rolled solution can’t account for any of those. In order to be sure that a user isn’t interacting in some way you would also need to attach listeners to every kind of interaction event ( scroll , touch , click ), even if you don’t need them for functionality, just so that you can be absolutely sure that the user isn’t interacting. The browser, on the other hand, knows exactly how much time is available at the end of the frame, and if the user is interacting, and so through requestIdleCallback we gain an API that allows us to make use of any spare time in the most efficient way possible.

Let’s take a look at it in a little more detail and see how we can make use of it.

Checking for requestIdleCallback

It’s early days for requestIdleCallback , so before using it you should check that it’s available for use:

You can also shim its behavior, which requires falling back to setTimeout :

Using setTimeout isn't great because it doesn't know about idle time like requestIdleCallback does, but since you would call your function directly if requestIdleCallback wasn't available, you are no worse off shimming in this way. With the shim, should requestIdleCallback be available, your calls will be silently redirected, which is great.

For now, though, let’s assume that it exists.

Calling requestIdleCallback is very similar to requestAnimationFrame in that it takes a callback function as its first parameter:

When myNonEssentialWork is called, it will be given a deadline object which contains a function which returns a number indicating how much time remains for your work:

The timeRemaining function can be called to get the latest value. When timeRemaining() returns zero you can schedule another requestIdleCallback if you still have more work to do:

Guaranteeing your function is called

What do you do if things are really busy? You might be concerned that your callback may never be called. Well, although requestIdleCallback resembles requestAnimationFrame , it also differs in that it takes an optional second parameter: an options object with a timeout property. This timeout, if set, gives the browser a time in milliseconds by which it must execute the callback:

If your callback is executed because of the timeout firing you’ll notice two things:

  • timeRemaining() will return zero.
  • The didTimeout property of the deadline object will be true.

If you see that the didTimeout is true, you will most likely just want to run the work and be done with it:

Because of the potential disruption this timeout can cause to your users (the work could cause your app to become unresponsive or janky) be cautious with setting this parameter. Where you can, let the browser decide when to call the callback.

Using requestIdleCallback for sending analytics data

Let’s take a look using requestIdleCallback to send analytics data. In this case, we probably would want to track an event like -- say -- tapping on a navigation menu. However, because they normally animate onto the screen, we will want to avoid sending this event to Google Analytics immediately. We will create an array of events to send and request that they get sent at some point in the future:

Now we will need to use requestIdleCallback to process any pending events:

Here you can see I’ve set a timeout of 2 seconds, but this value would depend on your application. For analytics data, it makes sense that a timeout would be used to ensure data is reported in a reasonable timeframe rather than just at some point in the future.

Finally we need to write the function that requestIdleCallback will execute.

For this example I assumed that if requestIdleCallback didn’t exist that the analytics data should be sent immediately. In a production application, however, it would likely be better to delay the send with a timeout to ensure it doesn’t conflict with any interactions and cause jank.

Using requestIdleCallback to make DOM changes

Another situation where requestIdleCallback can really help performance is when you have non-essential DOM changes to make, such as adding items to the end of an ever-growing, lazy-loaded list. Let’s look at how requestIdleCallback actually fits into a typical frame.

A typical frame.

It’s possible that the browser will be too busy to run any callbacks in a given frame, so you shouldn’t expect that there will be any free time at the end of a frame to do any more work. That makes it different to something like setImmediate , which does run per frame.

If the callback is fired at the end of the frame, it will be scheduled to go after the current frame has been committed, which means that style changes will have been applied, and, importantly, layout calculated. If we make DOM changes inside of the idle callback, those layout calculations will be invalidated. If there are any kind of layout reads in the next frame, e.g. getBoundingClientRect , clientWidth , etc, the browser will have to perform a Forced Synchronous Layout , which is a potential performance bottleneck.

Another reason not trigger DOM changes in the idle callback is that the time impact of changing the DOM is unpredictable, and as such we could easily go past the deadline the browser provided.

The best practice is to only make DOM changes inside of a requestAnimationFrame callback, since it is scheduled by the browser with that type of work in mind. That means that our code will need to use a document fragment, which can then be appended in the next requestAnimationFrame callback. If you are using a VDOM library, you would use requestIdleCallback to make changes, but you would apply the DOM patches in the next requestAnimationFrame callback, not the idle callback.

So with that in mind, let’s take a look at the code:

Here I create the element and use the textContent property to populate it, but chances are your element creation code would be more involved! After creating the element scheduleVisualUpdateIfNeeded is called, which will set up a single requestAnimationFrame callback that will, in turn, append the document fragment to the body:

All being well we will now see much less jank when appending items to the DOM. Excellent!

  • Is there a polyfill? Sadly not, but there is a shim if you want to have a transparent redirection to setTimeout . The reason this API exists is because it plugs a very real gap in the web platform. Inferring a lack of activity is difficult, but no JavaScript APIs exist to determine the amount of free time at the end of the frame, so at best you have to make guesses. APIs like setTimeout , setInterval , or setImmediate can be used to schedule work, but they are not timed to avoid user interaction in the way that requestIdleCallback is.
  • What happens if I overrun the deadline? If timeRemaining() returns zero, but you opt to run for longer, you can do so without fear of the browser halting your work. However, the browser gives you the deadline to try and ensure a smooth experience for your users, so unless there’s a very good reason, you should always adhere to the deadline.
  • Is there maximum value that timeRemaining() will return? Yes, it’s currently 50ms. When trying to maintain a responsive application, all responses to user interactions should be kept under 100ms. Should the user interact the 50ms window should, in most cases, allow for the idle callback to complete, and for the browser to respond to the user’s interactions. You may get multiple idle callbacks scheduled back-to-back (if the browser determines that there’s enough time to run them).
  • Is there any kind of work I shouldn’t do in a requestIdleCallback? Ideally the work you do should be in small chunks (microtasks) that have relatively predictable characteristics. For example, changing the DOM in particular will have unpredictable execution times, since it will trigger style calculations, layout, painting, and compositing. As such you should only make DOM changes in a requestAnimationFrame callback as suggested above. Another thing to be wary of is resolving (or rejecting) Promises, as the callbacks will execute immediately after the idle callback has finished, even if there is no more time remaining.
  • Will I always get a requestIdleCallback at the end of a frame? No, not always. The browser will schedule the callback whenever there is free time at the end of a frame, or in periods where the user is inactive. You shouldn’t expect the callback to be called per frame, and if you require it to run within a given timeframe you should make use of the timeout.
  • Can I have multiple requestIdleCallback callbacks? Yes, you can, very much as you can have multiple requestAnimationFrame callbacks. It’s worth remembering, though, that if your first callback uses up the time remaining during its callback then there will be no more time left for any other callbacks. The other callbacks will then have to wait until the browser is next idle before they can be run. Depending on the work you’re trying to get done, it may be better to have a single idle callback and divide the work in there. Alternatively you can make use of the timeout to ensure that no callbacks get starved for time.
  • What happens if I set a new idle callback inside of another? The new idle callback will be scheduled to run as soon as possible, starting from the next frame (rather than the current one).

requestIdleCallback is an awesome way to make sure you can run your code, but without getting in the user’s way. It's simple to use, and very flexible. It's still early days, though, and the spec isn't fully settled, so any feedback you have is welcome.

Check it out in Chrome Canary, give it a spin for your projects, and let us know how you get on!

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License , and code samples are licensed under the Apache 2.0 License . For details, see the Google Developers Site Policies . Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2015-08-19 UTC.

Using requestIdleCallback for long running computations

Oct 16, 2018

One of the ways developers have tipically tried to keep a smooth web application, without interfering with the browser’s animation and response to input, is to use a Web Worker for long running computations. For example, in the Prism.js (a library for syntax highlighting) API there’s an async parameter to choose “Whether to use Web Workers to improve performance and avoid blocking the UI when highlighting very large chunks of code” .

This is perfectly fine, but web workers are not so easy to use or debug. To take Prism.js again as an example, the option I mentioned earlier is false by default. Why?

In most cases, you will want to highlight reasonably sized chunks of code, and this will not be needed. Furthermore, using Web Workers is actually slower than synchronously highlighting, due to the overhead of creating and terminating the Worker. It just appears faster in these cases because it doesn’t block the main thread. In addition, since Web Workers operate on files instead of objects, plugins that hook on core parts of Prism (e.g. modify language definitions) will not work unless included in the same file (using the builder in the Download page will protect you from this pitfall). Lastly, Web Workers cannot interact with the DOM and most other APIs (e.g. the console), so they are notoriously hard to debug.”

Another alternative to achieve the same result, without using Web Workers and making things more difficult, is to use requestIdleCallback . This function allows a callback to be scheduled when the browser is idle, enabling us to perform background work / low priority work on the main thread without impacting animations / input response. N.B.: This will still be slower than synchronous, but might be cheaper than a Web Worker since you don’t have to pay the price of the Worker initialization.

Here’s an example, using promises and asynchronous functions we can also avoid callback hell and keep using normal loops.

I’m doing something similar in my Searchfox in Phabricator extension , to operate on one source line at a time and avoid slowing down the normal Phabricator operation. Here’s where I’m doing it .

The Code Framework

JavaScript’s requestIdleCallback: A Deep Dive

safari requestidlecallback alternative

One of JavaScript’s most intriguing features is the requestIdleCallback function, which allows developers to optimize the performance of their applications by scheduling non-essential work during idle periods. In this blog post, we’ll take a deep dive into the requestIdleCallback function, exploring its benefits, use cases, and how to implement it in your own projects.

Introduction to requestIdleCallback

requestIdleCallback is a JavaScript function that allows developers to schedule non-essential tasks to run during periods when the browser’s main thread is idle. This helps to ensure that important tasks, such as rendering and user interactions, are not delayed by less critical work.

The requestIdleCallback function takes two arguments:

  • A callback function that will be executed when the browser enters an idle period.
  • An optional configuration object that includes a timeout property, which specifies a maximum time (in milliseconds) that the browser should wait before executing the callback function, regardless of whether it is idle or not.

Here’s a basic example of how to use requestIdleCallback :

Benefits of Using requestIdleCallback

Using requestIdleCallback to schedule non-essential work can provide several benefits to your application, including:

  • Improved performance: By deferring non-critical tasks to idle periods, your application can prioritize essential work, such as rendering and user interactions. This can help to ensure a smoother, more responsive user experience.
  • Increased efficiency: By scheduling work during idle periods, your application can make better use of available system resources and potentially reduce power consumption.
  • Easier maintenance: By organizing your code to separate essential and non-essential tasks, you can make your application easier to understand and maintain.

Understanding the IdleDeadline Object

When your callback function is executed by requestIdleCallback , it is passed an IdleDeadline object as its only argument. This object provides information about the current idle period, including:

  • timeRemaining() : A method that returns the estimated time (in milliseconds) remaining in the current idle period.
  • didTimeout : A boolean property that indicates whether the callback was executed because the optional timeout period elapsed.

Here’s an example of how to use the IdleDeadline object within your callback function:

Implementing requestIdleCallback

To implement requestIdleCallback in your application, follow these steps:

  • Identify non-essential tasks that can be deferred to idle periods.
  • Create a callback function that performs these tasks, making use of the IdleDeadline object to manage the available time.
  • Schedule the callback function using requestIdleCallback , and optionally specify a timeout value if desired.

Use Cases and Examples

requestIdleCallback can be used in a variety of scenarios where non-essential work can be deferred to improve performance. Some common use cases include:

  • Analytics: Defer sending analytics data to a server until an idle period, to avoid impacting user interactions.
  • Image loading: Lazy-load images or other resources during idle periods, to reduce the initial page load time.
  • Code splitting: Load non-critical JavaScript modules during idle periods, to improve initial page load performance.

Here’s an example of using requestIdleCallback to lazy-load images:

Browser Support and Polyfills

requestIdleCallback is currently supported in most modern browsers, including Chrome, Firefox, and Opera. However, it is not supported in Internet Explorer or Safari.

If you need to support browsers that do not natively implement requestIdleCallback , you can use a polyfill, such as requestidlecallback-polyfill .

requestIdleCallback is a powerful tool for optimizing the performance of your JavaScript applications by scheduling non-essential work during idle periods. By understanding its benefits, use cases, and implementation details, you can harness its potential to create more efficient, responsive, and maintainable applications.

Leave a Reply Cancel reply

You must be logged in to post a comment.

safari requestidlecallback alternative

  • Login/Sign-Up

Kalan's Blog

Kalan 頭像照片,在淡水拍攝,淺藍背景

四零二曜日 電子報上線啦!訂閱訂起來

Software Engineer / Taiwanese / Life in Fukuoka This blog supports RSS feed (all content), you can click RSS icon or setup through third-party service. If there are special styles such as code syntax in the technical article, it is still recommended to browse to the original website for the best experience.

我會把一些不成文的筆記或是最近的生活雜感放在 短筆記 ,如果有興趣的話可以來看看唷!

Please notice that currenly most of posts are translated by AI automatically and might contain lots of confusion. I'll gradually translate the post ASAP

RequestidLecallBack - Make good use of free time

Many web pages contain various script that need to be executed, and of course, there are priorities. For example, rendering UI, registering interactive events, calling APIs to fetch data, etc. are high-priority tasks, while less important tasks include analytic scripts, lazy loading, and initializing less important events.

What is considered Idle?

How can we know when the browser is in an Idle state? This is a complex question. The browser schedules a series of tasks for us, such as parsing HTML, CSS, JavaScript, rendering UI, API calls, fetching and parsing images, GPU acceleration, etc. To know when it is idle, we need to understand how the browser's scheduling works. Fortunately, requestIdleCallback solves this problem for us.

Introduction to requestIdleCallback

requestIdleCallback executes at the end of a frame, but it is not guaranteed to run in every frame. The reason is simple - we cannot guarantee that we will have time at the end of every frame, so we cannot guarantee the execution time of requestIdleCallback .

Upon closer inspection, requestIdleCallback feels a bit like a context switch. You can perform some tasks between frames, pause for a moment, and then continue execution.

requestIdleCallback(fn, {timeout})

In addition, the second parameter, options, has a timeout option. If the browser doesn't call within the specified timeout, you can use this timeout to force the browser to stop its current work and call the callback.

This is not an appropriate usage because we use idle for tasks that are not important, and it is not necessary to interrupt the current work for them. The browser provides us with this flexibility, and sometimes we still want events to be triggered within a certain time frame.

cancelIdleCallback(id)

requestIdleCallback() returns an ID, and we can use cancelIdleCallback(id) to cancel unnecessary idle callbacks.

Will requestIdleCallback be interrupted?

The deadline parameter indicates how much time you have to complete the task within a frame. The callback function can access this parameter. According to the official documentation, even if the time exceeds the deadline, the browser will not forcibly interrupt your task . It just hopes that you can complete the task within the deadline to provide the best user experience.

deadline.timeRemaining() returns the remaining available time.

What happens if DOM operations are performed in requestIdleCallback?

Imagine this - as mentioned earlier, requestIdleCallback runs at the end of a frame, indicating that the browser has completed the work of recalculating, layout, and painting. If you modify the DOM at this point, it forces the browser to schedule recalculating style, layout, and painting all over again.

What happens if requestIdleCallback is called within requestIdleCallback?

Calling requestIdleCallback within requestIdleCallback is valid. However, this callback will be scheduled for the next frame . (Actually, it may not be the next frame, depending on the browser's scheduling.)

Example, please!

Let's say we have multiple users, and when the mouse hovers over their avatars, a personal introduction is displayed. To make use of the idle time, we can use requestIdleCallback to secretly fetch the necessary API data. If the data hasn't been fetched yet, we can then call the API to retrieve it.

In this example, we use requestIdleCallback to fetch user data and store it. Later, when the user hovers over the avatar, we can directly display the introduction. If the data hasn't been fetched yet, we fetch it again using fetchUser .

To demonstrate the effect of requestIdleCallback , this example may seem a bit complicated. It requires maintaining a queue to check if the data has been fetched, and if the mouseover event is triggered, we need to check userIntro again to see if it has a value. It can become more complex during development. Fetching data for multiple users at once may be more convenient. However, this depends on the specific requirements and use cases.

Another common scenario is tracking user actions, such as button clicks, play events, viewing time, etc. We can collect these events first and then use requestIdleCallback to send them all at once. For example:

Here, we added a timeout to ensure that the browser calls the schedule function.

How about React?

To avoid unnecessary work blocking the main thread, we can integrate React hooks and put all unnecessary work inside useIdleCallback .

Some Questions

The examples above are for demonstration purposes only. In reality, there are many issues to address, such as managing the queue, managing the timeout , and even marking the priority of tasks to ensure proper execution order. These are all areas that can be optimized.

Browser support for requestIdleCallback is not yet widespread:

Browser Support

In React's Fiber, a similar mechanism is used to handle work. In the past, when performing work, the main thread could become blocked due to a deep call stack or too many updateQueue items, causing long update times. The Fiber mechanism breaks the work into smaller pieces. If there are higher-priority tasks, it processes them first and then continues with other work.

Remember a debug process — connection

Introduction to Goworker — Implementing Workers with Redis

If you found this article helpful, please consider buy me a drink ☕️ It'll make my ordinary day shine✨

  • Skip to main content
  • Select language
  • Skip to search

window.requestIdleCallback()

This is an experimental technology Because this technology's specification has not stabilized, check the compatibility table for usage in various browsers. Also note that the syntax and behavior of an experimental technology is subject to change in future versions of browsers as the specification changes.

The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response. Functions are generally called in first-in-first-out order; however, callbacks which have a timeout specified may be called out-of-order if necessary in order to run them before the timeout elapses.

You can call requestIdleCallback() within an idle callback function to schedule another callback to take place no sooner than the next pass through the event loop.

Return value

An ID which can be used to cancel the callback by passing it into the window.cancelIdleCallback()  method.

  • timeout : If timeout is specified and has a positive value, and the callback has not already been called by the time timeout milliseconds have passed, the timeout will be called during the next idle period, even if doing so risks causing a negative performance impact..

See our complete example in the article Cooperative Scheduling of Background Tasks API .

Specifications

Browser compatibility.

[1] requestIdleCallback() is implemented in Firefox 53 but is disabled by default; to enable it, set the preference dom.requestIdleCallback.enabled to true . It is enabled by default starting in Firefox 55.

  • window.cancelIdleCallback()
  • IdleDeadline
  • window.setTimeout()
  • window.setInterval()

Document Tags and Contributors

  • DOM Reference
  • JavaScript timers
  • requestIdleCallback
  • applicationCache
  • controllers
  • defaultStatus
  • devicePixelRatio
  • dialogArguments
  • directories
  • or <object>) in which the window is embedded, or null if the element is either top-level or is embedded into a document with a different script origin; that is, in cross-origin situations." href="frameElement.html"> frameElement
  • innerHeight
  • isSecureContext
  • or <iframe> elements) in the window." href="length.html"> length
  • localStorage
  • locationbar
  • messageManager
  • mozAnimationStartTime
  • mozInnerScreenX
  • mozInnerScreenY
  • mozPaintCount
  • onafterprint
  • onanimationcancel
  • onanimationend
  • onanimationiteration
  • onappinstalled
  • onbeforeinstallprompt
  • onbeforeprint
  • onbeforeunload
  • oncontextmenu
  • ondevicelight
  • ondevicemotion
  • ondeviceorientation
  • ondeviceorientationabsolute
  • ondeviceproximity
  • ongotpointercapture
  • onhashchange
  • element value changes." href="../GlobalEventHandlers/oninput.html"> oninput
  • onlanguagechange
  • element, etc., which fires when the resource has loaded." href="../../../DOM/window.onload.html"> onload
  • onloadstart
  • onlostpointercapture
  • onmousedown
  • onmousemove
  • onmouseover
  • onmozbeforepaint
  • onpointercancel
  • onpointerdown
  • onpointerenter
  • onpointerleave
  • onpointermove
  • onpointerout
  • onpointerover
  • onpointerup
  • onrejectionhandled
  • onselectionchange
  • onselectstart
  • ontouchcancel
  • ontouchmove
  • ontouchstart
  • ontransitioncancel
  • ontransitionend
  • onunhandledrejection
  • onuserproximity
  • onvrdisplayconnected
  • onvrdisplaydisconnected
  • onvrdisplaypresentchange
  • outerHeight
  • performance
  • personalbar
  • sessionStorage
  • speechSynthesis
  • cancelAnimationFrame()
  • cancelIdleCallback()
  • captureEvents()
  • clearImmediate()
  • clearInterval()
  • clearTimeout()
  • convertPointFromNodeToPage()
  • createImageBitmap()
  • getAttention()
  • getComputedStyle()
  • getDefaultComputedStyle()
  • getSelection()
  • matchMedia()
  • openDialog()
  • postMessage()
  • releaseEvents()
  • s in order to improve performance and battery life." href="../window.requestAnimationFrame.html"> requestAnimationFrame()
  • requestIdleCallback()
  • routeEvent()
  • scrollByLines()
  • scrollByPages()
  • setCursor()
  • setImmediate()
  • setInterval()
  • setTimeout()
  • showModalDialog()
  • sizeToContent()
  • updateCommands()
  • autocomplete
  • autocompleteerror
  • DOMContentLoaded
  • afterscriptexecute
  • beforeprint
  • beforescriptexecute
  • beforeunload
  • contextmenu
  • languagechange
  • readystatechange
  • loadedmetadata
  • canplaythrough
  • volumechange
  • durationchange
  • unhandledrejection
  • rejectionhandled
  • BeforeUnloadEvent
  • DOMStringMap
  • GlobalEventHandlers
  • HTMLAnchorElement
  • HTMLAreaElement
  • HTMLAudioElement
  • HTMLBRElement
  • HTMLBaseElement
  • HTMLBaseFontElement
  • HTMLBodyElement
  • HTMLButtonElement
  • HTMLCanvasElement
  • HTMLContentElement
  • HTMLDListElement
  • HTMLDataElement
  • HTMLDataListElement
  • HTMLDialogElement
  • HTMLDivElement
  • HTMLDocument
  • HTMLElement
  • HTMLEmbedElement
  • HTMLFieldSetElement
  • HTMLFormControlsCollection
  • HTMLFormElement
  • HTMLFrameSetElement
  • HTMLHRElement
  • HTMLHeadElement
  • HTMLHeadingElement
  • HTMLHtmlElement
  • HTMLIFrameElement
  • HTMLImageElement
  • HTMLInputElement
  • HTMLIsIndexElement
  • HTMLKeygenElement
  • HTMLLIElement
  • HTMLLabelElement
  • HTMLLegendElement
  • HTMLLinkElement
  • HTMLMapElement
  • HTMLMediaElement
  • HTMLMetaElement
  • HTMLMeterElement
  • HTMLModElement
  • HTMLOListElement
  • HTMLObjectElement
  • HTMLOptGroupElement
  • HTMLOptionElement
  • HTMLOptionsCollection
  • HTMLOutputElement
  • HTMLParagraphElement
  • HTMLParamElement
  • HTMLPictureElement
  • HTMLPreElement
  • HTMLProgressElement
  • HTMLQuoteElement
  • HTMLScriptElement
  • HTMLSelectElement
  • HTMLShadowElement
  • HTMLSourceElement
  • HTMLSpanElement
  • HTMLStyleElement
  • HTMLTableCaptionElement
  • HTMLTableCellElement
  • HTMLTableColElement
  • HTMLTableDataCellElement
  • HTMLTableElement
  • HTMLTableHeaderCellElement
  • HTMLTableRowElement
  • HTMLTableSectionElement
  • HTMLTemplateElement
  • HTMLTextAreaElement
  • HTMLTimeElement
  • HTMLTitleElement
  • HTMLTrackElement
  • HTMLUListElement
  • HTMLUnknownElement
  • HTMLVideoElement
  • HashChangeEvent
  • MessageChannel
  • MessageEvent
  • MessagePort
  • NavigatorGeolocation
  • NavigatorID
  • NavigatorLanguage
  • NavigatorOnLine
  • NavigatorPlugins
  • PageTransitionEvent
  • PluginArray
  • PopStateEvent
  • PortCollection
  • PromiseRejectionEvent
  • RadioNodeList
  • Transferable
  • ValidityState
  • WindowBase64
  • WindowEventHandlers
  • WindowTimers

requestIdleCallback()

Cooperative scheduling of background tasks.

This document defines an API that web page authors can use to cooperatively schedule background tasks such that they do not introduce delays to other high priority tasks that share the same event loop, such as input processing, animations and frame compositing. The user agent is in a better position to determine when background tasks can be run without introducing user-perceptible delays or jank in animations and input response, based on its knowledge of currently scheduled tasks, vsync deadlines, user-interaction and so on. Using this API should therefore result in more appropriate scheduling of background tasks during times when the browser would otherwise be idle.

The Web Performance Working Group maintains a test suite for the specification. Please see the Working Group's implementation report . Vendors interested in implementing this document SHOULD join the mailing lists below and take part in the discussions.

Introduction

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. Examples of such background tasks include recording analytics data, long running data processing operations, client-side templating and pre-rendering of content likely to become visible in the near future. These tasks must share the event loop with other time-critical operations, such as reacting to input and performing script-based animations using {{AnimationFrameProvider/requestAnimationFrame()}}. These background tasks are typically performed by scheduling a callback using {{WindowOrWorkerGlobalScope/setTimeout()}} and running the background task during that callback.

A disadvantage of this approach is that the author of the script has no way to inform the user-agent as to whether a given {{WindowOrWorkerGlobalScope/setTimeout()}} callback is time-critical or could be delayed until the browser is otherwise idle. In addition, the user agent 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. As a result, the easiest way forward is for the author is to simply call {{WindowOrWorkerGlobalScope/setTimeout()}} with a very small value, and then execute the minimum possible chunk of work in the resulting callback and reschedule additional work with another call to {{WindowOrWorkerGlobalScope/setTimeout()}}. This is less than optimal because there is extra overhead from having to post many small tasks on the user agent's event loop and schedule their execution. It also relies on the user-agent interleaving other time-critical work between each of these callbacks appropriately, which is difficult since the user-agent can't make accurate assumptions on how long each of these callbacks are likely to take.

The API described in this document allows script authors to request the user-agent to schedule a callback when it would otherwise be idle. The user agent provides an estimation of how long it expects to remain idle as a deadline passed to the callback. The page author can use the deadline to ensure that these background tasks don't impact latency-critical events such as animation and input response.

Here is an example of using the API to write a background task.

Idle Periods

After input processing, rendering and compositing for a given frame has been completed, the user agent's main thread often becomes idle until either: the next frame begins; another pending task becomes eligible to run; or user input is received. This specification provides a means to schedule execution of callbacks during this otherwise idle time via a {{Window/requestIdleCallback()}} API.

Callbacks posted via the {{Window/requestIdleCallback()}} API become eligible to run during user agent defined idle periods. When an idle callback is run it will be given a deadline which corresponds to the end of the current idle period. The decision as to what constitutes an idle period is user agent defined, however the expectation is that they occur in periods of quiescence where the browser expects to be idle.

One example of an idle period is the time between committing a given frame to the screen and starting processing on the next frame during active animations, as shown in . Such idle periods will occur frequently during active animations and screen updates, but will typically be very short (i.e., less than 16ms for devices with a 60Hz vsync cycle).

The web-developer should be careful to account for all work performed by operations during an idle callback. Some operations, such as resolving a promise or triggering a page layout, may cause subsequent tasks to be scheduled to run after the idle callback has finished. In such cases, the application should account for this additional work by yielding before the deadline expires to allow these operations to be performed before the next frame deadline.

Another example of an idle period is when the user agent is idle with no screen updates occurring. In such a situation the user agent may have no upcoming tasks with which it can bound the end of the idle period. In order to avoid causing user-perceptible delays in unpredictable tasks, such as processing of user input, the length of these idle periods should be capped to a maximum value of 50ms . Once an idle period is finished the user agent can schedule another idle period if it remains idle, as shown in , to enable background work to continue to occur over longer idle time periods.

During an idle period the user agent will run idle callbacks in FIFO order until either the idle period ends or there are no more idle callbacks eligible to be run. As such, the user agent will not necessarily run all currently posted idle callbacks within a single idle period. Any remaining idle tasks are eligible to run during the next idle period.

To deliver the best performance developers are encouraged to eliminate unnecessary callbacks (e.g. requestAnimationFrame, setTimeout, and so on) that do not perform meaningful work; do not keep such callbacks firing and waiting for events to react, instead schedule them as necessary to react to events once they become available. Such pattern improves overall efficiency, and enables the user agent to schedule long idle callbacks (up to 50ms) that can be used to efficiently perform large blocks of background work.

Only idle tasks which posted before the start of the current idle period are eligible to be run during the current idle period. As a result, if an idle callback posts another callback using {{Window/requestIdleCallback()}}, this subsequent callback won't be run during the current idle period. This enables idle callbacks to re-post themselves to be run in a future idle period if they cannot complete their work by a given deadline - i.e., allowing code patterns like the following example, without causing the callback to be repeatedly executed during a too-short idle period:

At the start of the next idle period newly posted idle callbacks are appended to the end of the runnable idle callback list, thus ensuring that reposting callbacks will be run round-robin style, with each callback getting a chance to be run before that of an earlier task's reposted callback.

Future versions of this specification could allow other scheduling strategies. For example, schedule idle callback within the same idle period, a period that has at least X milliseconds of idle time, and so on. Current specification only supports the case for scheduling into the next idle period, at which time the callback can execute its logic, or repost itself into the next idle period.

When the user agent determines that the web page is not user visible it can throttle idle periods to reduce the power usage of the device, for example, only triggering an idle period every 10 seconds rather than continuously.

A final subtlety to note is that there is no guarantee that a user agent will have any idle CPU time available during heavy page load. As such, it is entirely acceptable that the user agent does not schedule any idle period, which would result in the idle callbacks posted via the {{Window/requestIdleCallback()}} API being postponed for a potentially unbounded amount of time. For cases where the author prefers to execute the callback within an idle period, but requires a time bound within which it can be executed, the author can provide the timeout property in the options argument to {{Window/requestIdleCallback()}}: if the specified timeout is reached before the callback is executed within an idle period, a task is queued to execute it.

The maximum deadline of 50ms is derived from studies [[RESPONSETIME]] which show that that a response to user input within 100ms is generally perceived as instantaneous to humans. Capping idle deadlines to 50ms means that even if the user input occurs immediately after the idle task has begun, the user agent still has a remaining 50ms in which to respond to the user input without producing user perceptible lag.

The IDL fragments in this specification MUST be interpreted as required for conforming IDL fragments.

This specification defines a single conformance class:

{{Window}} interface extensions

The partial interface in the IDL fragment below is used to expose the {{Window/requestIdleCallback()}} operation on the {{Window}} object.

Each {{Window}} has:

  • A list of idle request callbacks . The list MUST be initially empty and each entry in this list is identified by a number, which MUST be unique within the list for the lifetime of the {{Window}} object.
  • A list of runnable idle callbacks . The list MUST be initially empty and each entry in this list is identified by a number, which MUST be unique within the list of the lifetime of the {{Window}} object.
  • An idle callback identifier , which is a number which MUST initially be zero.

The requestIdleCallback() method

When {{Window/requestIdleCallback}} (|callback|, |options|) is invoked with a given IdleRequestCallback and optional IdleRequestOptions , the user agent MUST run the following steps:

  • Let window be this {{Window}} object.
  • Increment the window 's idle callback identifier by one.
  • Let handle be the current value of window 's idle callback identifier .
  • Push callback to the end of window 's list of idle request callbacks , associated with handle .

The following steps run in parallel and queue a timer similar to setTimeout() if the optional timeout property is provided. From here, the idle and timeout callbacks are raced and cancel each other—e.g. if the idle callback is scheduled first, then it cancels the timeout callback, and vice versa.

  • Wait for timeout milliseconds.
  • Wait until all invocations of this algorithm, whose timeout added to their posted time occurred before this one's, have completed.

This is intended to allow user agents to pad timeouts as needed to optimise the power usage of the device. For example, some processors have a low-power mode where the granularity of timers is reduced; on such platforms, user agents can slow timers down to fit this schedule instead of requiring the processor to use the more accurate mode with its associated higher power usage.

  • Queue a task on the queue associated with the idle-task task source , which performs the invoke idle callback timeout algorithm , passing handle and window as arguments.

{{Window/requestIdleCallback()}} only schedules a single callback, which will be executed during a single idle period . If the callback cannot complete its work before the given deadline then it should call {{Window/requestIdleCallback()}} again (which may be done from within the callback) to schedule a future callback for the continuation of its task, and exit immediately to return control back to the event loop .

The cancelIdleCallback() method

The {{Window/cancelIdleCallback()}} method is used to cancel a previously made request to schedule an idle callback. When {{Window/cancelIdleCallback}} (|handle|) is invoked, the user agent MUST run the following steps:

  • Find the entry in either the window 's list of idle request callbacks or list of runnable idle callbacks that is associated with the value handle .
  • If there is such an entry, remove it from both window 's list of idle request callbacks and the list of runnable idle callbacks .

{{Window/cancelIdleCallback()}} might be invoked for an entry in window 's list of idle request callbacks or the list of runnable idle callbacks . In either case the entry should be removed from the list so that the callback does not run.

The IdleDeadline interface

When the timeRemaining() method is invoked on an IdleDeadline object it MUST return the remaining duration before the deadline expires as a {{DOMHighResTimeStamp}}, which SHOULD be enough to allow measurement while preventing timing attack - see "Privacy and Security" section of [[HR-TIME]]. This value is calculated by performing the following steps:

  • Let now be a {{DOMHighResTimeStamp}} representing current high resolution time in milliseconds.
  • Let deadline be the result of calling {{IdleDeadline}}'s get deadline time algorithm.
  • Let timeRemaining be deadline - now .
  • If timeRemaining is negative, set it to 0.
  • Return timeRemaining .

Each IdleDeadline has an associated timeout , which is initially false. The didTimeout getter MUST return timeout .

The invoke idle callback timeout algorithm sets timeout to true to specify that the callback is being executed outside an idle period, due to it having exceeded the value of the IdleRequestOptions 's timeout property which was passed when the callback was registered.

Start an idle period algorithm

The algorithm is called by the event loop processing model when it determines that the event loop is otherwise idle.

This is intended to allow user agents to delay the start of idle periods as needed to optimise the power usage of the device. For example, if the {{Document}}'s [=Document/visibility state=] is "hidden" then the user agent can throttle idle period generation, for example limiting the Document to one idle period every 10 seconds to optimize for power usage.

  • Let pending_list be window 's list of idle request callbacks .
  • Let run_list be window 's list of runnable idle callbacks .
  • Append all entries from pending_list into run_list preserving order.
  • Clear pending_list .
  • Queue a task on the queue associated with the idle-task task source , which performs the steps defined in the invoke idle callbacks algorithm with window and getDeadline as parameters.

The time between now and the deadline is referred to as the idle period . There can only be one idle period active at a given time for any given {{Window}}. The idle period can end early if the user agent determines that it is no longer idle. If so, the next idle period cannot start until after deadline .

Invoke idle callbacks algorithm

To invoke idle callbacks algorithm given {{Window}} window and getDeadline , an algorithm returning a {{DOMHighResTimeStamp}}: [[HR-TIME]].

  • Let now be the current time.
  • Pop the top callback from window 's list of runnable idle callbacks .
  • Let deadlineArg be a new IdleDeadline whose is getDeadline .
  • Call callback with deadlineArg as its argument. If an uncaught runtime script error occurs, then [=report the exception=].
  • If window 's list of runnable idle callbacks is not empty, queue a task which performs the steps in the invoke idle callbacks algorithm with getDeadline and window as a parameters and return from this algorithm

The user agent is free to end an idle period early, even if deadline has not yet occurred, by deciding return from the algorithm in step 1. For example, the user agent may decide to do this if it determines that higher priority work has become runnable.

Invoke idle callback timeout algorithm

The invoke idle callback timeout algorithm :

  • Let callback be the result of finding the entry in window 's list of idle request callbacks or the list of runnable idle callbacks that is associated with the value given by the handle argument passed to the algorithm.
  • Remove callback from both window 's list of idle request callbacks and the list of runnable idle callbacks .
  • Let deadlineArg be a new IdleDeadline . Set the get deadline time algorithm associated with deadlineArg to an algorithm returning now and set the timeout associated with deadlineArg to true .

Privacy Considerations

When an idle callback is scheduled the user agent provides an estimate of how long it expects to remain idle. This information can be used to estimate the time taken by other application tasks and related browser work within that frame. However, developers can already access this information via other means - e.g. mark beginning of the frame via requestAnimationFrame , estimate the time of the next frame, and use that information to compute "remaining time" within any callback.

To mitigate cache and statistical fingerprinting attacks, the resolution of the time estimates returned by the IdleDeadline interface should be [=coarsen time|coarsened=] based on [=environment settings object/cross-origin isolated capability=] to ensure this API is not exposing more information than what's exposed by other web-exposed timers. [[HR-TIME]]

Security Considerations

Acknowledgments.

The editors would like to thank the following people for contributing to this specification: Sami Kyostila, Alex Clarke, Boris Zbarsky, Marcos Caceres, Jonas Sicking, Robert O'Callahan, David Baron, Todd Reifsteck, Tobin Titus, Elliott Sprehn, Tetsuharu OHZEKI, Lon Ingram, Domenic Denicola, Philippe Le Hegaret and Anne van Kesteren.

logo

requestIdleCallback, Let the browser work for you!

By now you have probably heard of RequestAnimationFrame, if not the tldr is that RequestAnimationFrame lets the browser time animations for you to line up perfectly with the painting process, meaning you get more performant animations. This is a perfect example letting the platform work for you, and therefore gaining better performance since the browser can be smart about the whole thing. Since your PWA’s are going to be running mainly in a mobile environment, where computation resources are very limited, the more we can let the browser help us be fast, the better off we will be. A newer example of an api that lets the browser help us that you may not have heard of yet is requestIdleCallback . Lets dive into this new api and see how it can help make your next PWA lightning fast!

What exactly is requestIdleCallback?

requestIdleCallback is a new api that lets the browser execute code when it is idle. In this case idle means that the browser is currently at the end of a frame, has some free time and that the user is not interacting with the app in any way. requestIdleCallback will only fire the function passed to it when these two requirements are met, which does mean that if it does not have any idle time it may not actually execute the function passed to it. While this may sound like a bad thing, Hey I wrote this code, execute it damnit , requestIdleCallback has some handy features that we will see below to let you ensure that a bit of code is executed if it has to be.

Before we go into examples of how to use requestIdleCallback I thought I would introduce some instances where this new api comes in handy. First, most big sites and PWA’s use analytics of some kind so that the developer of that site can know how their users use this app. Now, imagine if your on a mobile device (and remember, not everyone has that brand new Google Pixel or Iphone 7), click on a menu and boom, that analaytics service kicks off some javascript to send the event to the analytics server. What happens when thread blocking JS runs when the browser is trying to animate? Jank, and sometimes lots of it. Now imagine that the developer used requestIdleCallback to send that analytics request. With requestIdleCallback the browser would have waited until it was idle (no painting or animating) and then would have sent the analytics request while it was idle. Now we have a jank free experience and still get to send those analytics! Second, imagine that we have a PWA that processes audio data using the Web Audio api. On mobile devices this can potentially be heavy on the cpu and do some thread locking. If we timed this work using requestIdleCallback the browser could then help us do this heavy work while the browser is idle and keep our PWA silky smooth!

One last thing before we use this api

As with all newer api’s we should always remember to fall back gracefully to older ways of doing things on browsers that do not yet support certain api’s. Current browser support for requestIdleCallback is as follows:

  • Chrome: Fully supported, available in Chrome since Chrome 47 (current stable version of Chrome is Chrome 55)
  • Firefox: Coming in Firefox 52 (current stable version of Firefox is Firefox 50)
  • Edge: Under consideration
  • Opera: Fully supported as of Opera 42 (current stable version of Opera is Opera 42)
  • Safari: Not supported, unfortunately could not find any info on when Safari plans to support requestIdleCallback

To test for requestIdleCallback suppport in your code and fall back gracefully for browsers with no support you can use this pattern.

With this code we will use requestIdleCallback when it is available and simply fall back to just executing our code when there is no support for it in the browser our app is running on.

Ok, so how do I use this thing?

If you have ever used RequestAnimationFrame then the requestIdleCallback api should feel pretty familiar to you. To use requestIdleCallback the first step is to pass it a callback. Our callback should be the function that we would like to schedule for idle time, doHeavyComputation in this example.

In a nutshell this is all you really need to use requestIdleCallback , but this usage does not guarantee that your code will be executed and also does not let you know how much time is actually available for that specific call to requestIdleCallback so lets expand on this example a little. The function that gets called by requestIdleCallback will receive a deadline object as a paramater. This deadline object offers some pretty handy information.

In this example we are using the deadline object to check if we have time left. While we do have free time we will do our heavy computation. The cool thing here is that if we run out of time doing this work then we can simply schedule another requestIdleCallback and try again next time the browser is idle. Now, say we want to ensure that some code will be ran even if requestIdleCallback runs out of time. requestIdleCallback takes a second paramater which lets us set a timeout. This forces the browser to finish executing our code by the time the timeout is reached. Now before I even show an example of this I would like to stress that you should only do this if you really really need to. The whole point of using requestIdleCallback is to schedule execution of code while the browser is idle so that we do not jank our PWA and it is definitely possible that when the timeout is reached the browser may still be busy, which means that executing our code may jank the world. So now that you are thoroughly warned about releasing the jank monster lets see an example of timeout in action.

As you can see here, we are now also checking for deadline.didTimeout . didTimeout will be true when our timeout has been reached which means that even though the browser has ran out of idle time we are still going to execute our code. Again, this can release the jank monster so be careful.

What does this have to do with my PWA ?

One of the big “selling points” of PWA’s is that they are able to be very light on resources and give an awesome experience on even the lowest of low end devices. The problem here is even if we have done everything else that a good PWA should do perf wise (fast load time, cache resources for even faster load time next load etc etc), if we execute javascript while the app is animating then we give our user a janky, slow experience, and who likes jank and slowness right? By taking advantage of perf oriented API’s like like requestIdleCallback we can let the platform our PWA’s all run on, the browser, help us succeed in our perf goals!

Hope you enjoyed this post! Make sure to tune in next time to learn about devices api’s and why they are important for PWA’s!

Navigation Menu

Search code, repositories, users, issues, pull requests..., provide feedback.

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly.

To see all available qualifiers, see our documentation .

  • Notifications You must be signed in to change notification settings

A requestIdleCallback shim/polyfill

aFarkas/requestIdleCallback

Folders and files, repository files navigation, requestidlecallback polyfill/shim.

This is a polyfill/shim for the requestIdleCallback and cancelIdleCallback API. Also fixes early API implementation.

For more information see the Cooperative Scheduling of Background Tasks Draft .

Installation

Include the "index.js" in your website and use requestIdleCallback and cancelIdleCallback according to the specification.

How it works

requestIdleCallback can't be really polyfilled. Therefore requestIdleCallback basically includes a throttle like function, that uses some heuristics to detect a) long running frames and b) user input as also DOM mutations to adapt accordingly. requestIdleCallback also tries to get the time right after a frame commit. The deadline.timeRemaining() either starts with 7ms or with 22ms for the first scheduled callback.

If multiple functions are scheduled with the requestIdleCallback shim for the same idle time, the shim makes sure to split those functions as soon as timeRemaining() is exceeded.

If you have a fast or a non-splittable task:

In case you have a heavy and splittable task you can use efficient script yielding technique:

Reading vs writing layout: requestIdleCallback is mainly for layout neutral or layout reading/measuring tasks. In case you want to write layout/manipulate the DOM consider using requestAnimationFrame instead.

Of course requestIdleCallback can also be combined with requestAnimationFrame :

Contributors 5

  • JavaScript 93.0%

Interactive guide on the requestIdleCallback() Web API

February 11, 2024 - 6 min read

The Web API requestIdleCallback() is undoubtedly one of the most underrated APIs in the web development ecosystem, offering the capability to schedule non-critical tasks for execution during idle periods in the browser.

The requestIdleCallback() method is globally accessible in the browser context and requires one mandatory callback function to run during idle periods as the first argument, with an optional options object as the second argument.

The general syntax in JavaScript is as follows:

Syntax with the timeout option in JavaScript :

Syntax in TypeScript :

  • The first argument is a callback function invoked by the browser during idle periods in the main thread. The callback receives an IdleDeadline interface object, containing the timeRemaining() method to check the time left for executing low priority task code and the didTimeout attribute to determine if the optional timeout has elapsed.
  • The second argument is an options object used to provide additional information. Presently, the only supported attribute in the options object is timeout , ensuring the callback is invoked before the specified timeout in milliseconds elapses. For instance, if the timeout is set to 3000 milliseconds and the callback hasn't been called after this duration, it takes priority and executes on the next available frame of the main thread. However, it's essential to note that while this timeout feature is beneficial, it could potentially lead to user experience issues such as stutter or lag if the user is actively interacting with the browser during this time.
  • The function returns an ID that can be used to cancel the callback if necessary, utilizing the cancelIdleCallback() function. To cancel the callback, pass the ID as an argument to the cancelIdleCallback() function.

Timeline of requestIdleCallback() Execution by the Browser

Understanding when the browser calls requestIdleCallback() provides insight into its usage.

As previously stated, the callback function passed to the requestIdleCallback() Web API executes during idle periods of the browser.

But Wait! What is an Idle Period in the Browser?

An idle period in the browser encompasses times when the user is not actively interacting with browser interfaces, such as not scrolling, minimizing the browser window, or being on another tab, as well as intervals between active animations.

In essence, it refers to periods when the browser's main thread is not occupied with high-priority tasks.

Thus, the requestIdleCallback() Web API can schedule low-priority tasks that do not require user attention but should execute when the browser's main thread is free.

Consider an example during two frames of an active animation. Let's assume that the browser is executing heavy, low-priority code during the second frame.

Below is an interactive demo for the animation example. Toggle the "requestIdleCallback() turned OFF" button to see how the API can help.

Frame 1 Starts

Frame 2 Starts

Without requestIdleCallback() function

Without utilizing the requestIdleCallback() function, user interactions may feel laggy as heavy, low-priority tasks are executed before the rendering process at the end of the second frame.

Using the requestIdleCallback() function allows us to schedule low-priority tasks during idle periods of the two frames. However, idle periods are not guaranteed for every frame in the browser. There may be scenarios where no idle periods occur, and the low-priority code is not scheduled for some time.

Employing the requestIdleCallback() API enables us to process tasks without introducing jank to the user interface, thereby enhancing the overall user experience.

Example: Sending User Analytics to the Server

An easy-to-understand example is sending user-related analytics to the server.

Since analytics are low-priority tasks that we can afford to run during the idle periods of the browser, the requestIdleCallback() Web API is a good candidate for this scenario.

Let's say we have a function called sendEvents({eventName: "mouse-click", id: "687212ed" }) that sends event information to the server for the currently logged-in user.

Since this is a low-priority task in our case, let's invoke the sendEvents() inside the callback function of the requestIdleCallback() Web API like this:

This function will be invoked by the browser and will send the event details to the server when the browser enters the next idle period.

However, there might be a chance to lag the user experience as we are not checking the allotted or the available idle period to execute our task.

To check exactly that, we can utilize the details regarding the current idle period time frame passed to the callback function as the first parameter.

The object has IdleInterface as its data type.

In the object, we can make use of the timeRemaining() method that returns the time allotted or the remaining time to execute the task in milliseconds before giving back control to the browser. If there is enough time to execute the task, which essentially means the time is greater than the value of 0 , we can schedule another requestIdleCallback() to be run in the next idle time frame of the browser with a timeout option if needed.

The code for the same will look like this:

Below is an interactive demo to see the remaining time for the above event task to run.

Time Remaining for the event task to run: 0 ms

Canceling an Already Scheduled Task

To cancel a task that has been previously scheduled with the requestIdleCallback() Web API, we can utilise the cancelIdleCallback() Web API within the global browser context.

  • The function requires the reference id returned by the requestIdleCallback() API as its first argument.

The code appears as follows:

This code efficiently cancels the execution of a task previously scheduled with requestIdleCallback() .

The requestIdleCallback() is a powerful tool in the web developer's toolkit and offers a wide variety of use cases to schedule low-priority tasks. It must be used with caution and practicality to achieve a better user experience.

  • https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
  • https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelIdleCallback
  • https://www.w3.org/TR/requestidlecallback/
  • https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline

safari requestidlecallback alternative

requestIdleCallback

API allowing the execution of JavaScript to be queued to run in idle browser time, either at the end of a frame or when the user is inactive. Also covers support for `cancelIdleCallback`. The API has similarities with `requestAnimationFrame`.

window api: requestidlecallback

requestidlecallback-polyfill

  • 0 Dependencies
  • 21 Dependents

requestIdleCallback polyfill

Simple polyfill and d.ts for requestIdleCallback .

The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response. Functions are generally called in first-in-first-out order; however, callbacks which have a timeout specified may be called out-of-order if necessary in order to run them before the timeout elapses.
You can call requestIdleCallback() within an idle callback function to schedule another callback to take place no sooner than the next pass through the event loop.

npm i requestidlecallback-polyfill

yarn add requestidlecallback-polyfill

  • Code from developers.google.com
  • Type definitions from rhysd/Mstdn
  • Code: Apache License 2.0
  • Type definitions: MIT
  • requestIdleCallback

Package Sidebar

Git github.com/pladaria/requestidlecallback-polyfill

github.com/pladaria/requestidlecallback-polyfill#readme

Downloads Weekly Downloads

MIT AND Apache-2.0

Unpacked Size

Total files, last publish.

6 years ago

Collaborators

pladaria

IMAGES

  1. Save Safari settings for websites you visit often

    safari requestidlecallback alternative

  2. requestIdleCallback is undefined and raises issues on Safari · Issue #1 · terkelg/workshy · GitHub

    safari requestidlecallback alternative

  3. Fix “Safari Can’t Open Page NSPOSIXErrorDomain:28” Error on Mac

    safari requestidlecallback alternative

  4. Can't Sign in to Google Account on Safari in iOS and iPadOS • macReports

    safari requestidlecallback alternative

  5. Adjusting Safari settings to enhance your online privacy

    safari requestidlecallback alternative

  6. How Do You Manage Safari? No Internet Connection

    safari requestidlecallback alternative

VIDEO

  1. all safari no flaps

  2. Tiger 31150 Alternate Build Lego MOC Tutorial Instructions

  3. Best Browser For iPhone's #ytshorts #arcsearch

  4. 𝐒𝐚𝐟𝐚𝐫𝐢 𝐆𝐮𝐢𝐝𝐞 𝐓𝐫𝐚𝐢𝐧𝐢𝐧𝐠

  5. 02 RequestIdleCallback

  6. BEST Safari Browser Alternative for iPhones! #iphone #apple

COMMENTS

  1. Window: requestIdleCallback() method

    The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response. Functions are generally called in first-in-first-out order; however, callbacks which have a timeout specified may be ...

  2. requestIdleCallback

    requestIdleCallback. API allowing the execution of JavaScript to be queued to run in idle browser time, either at the end of a frame or when the user is inactive. Also covers support for cancelIdleCallback. The API has similarities with requestAnimationFrame. 1 Can be enabled via the dom.requestIdleCallback.enabled flag.

  3. scroll events: requestAnimationFrame VS requestIdleCallback VS passive

    As we know, it's often advised to debounce scroll listeners so that UX is better when the user is scrolling. However, I've often found libraries and articles where influential people like Paul Lewis recommend using requestAnimationFrame.However as the web platform progress rapidly, it might be possible that some advice get deprecated over time.

  4. The requestIdleCallback approach can be a nice alternative to

    The requestIdleCallback approach can be a nice alternative to requestAnimationFrame or debouncing. But note that requestIdleCallback is not supported in Safari, so you have to shim it there. The spec is a good read: https: ...

  5. Making the Most of Idle Moments with requestIdleCallback()

    Scheduling the Callback. The syntax to schedule a callback during an idle period is: requestIdleCallback(callback[,options]); The first argument is the callback function we want executed when the browser is idle next. The second argument is an object we can pass in additional options with. Current the only option for this object is setting a ...

  6. RxJS: How to Use request Idle Callback

    Here, the work will be performed whenever the source emits a next notification. If we want to wait until the browser is idle before performing the work, we can use the idle observable, like this: source.pipe( bufferWhen(() => idle()), mergeMap((buffer) => buffer.map(work)) ); Here, our composed observable will wait until the browser is idle ...

  7. Using requestIdleCallback

    This timeout, if set, gives the browser a time in milliseconds by which it must execute the callback: // Wait at most two seconds before processing events. requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 }); If your callback is executed because of the timeout firing you'll notice two things:

  8. Using requestIdleCallback for long running computations

    Another alternative to achieve the same result, without using Web Workers and making things more difficult, is to use requestIdleCallback. This function allows a callback to be scheduled when the browser is idle, enabling us to perform background work / low priority work on the main thread without impacting animations / input response. N.B.:

  9. JavaScript's requestIdleCallback: A Deep Dive

    Benefits of Using requestIdleCallback. Using requestIdleCallback to schedule non-essential work can provide several benefits to your application, including:. Improved performance: By deferring non-critical tasks to idle periods, your application can prioritize essential work, such as rendering and user interactions. This can help to ensure a smoother, more responsive user experience.

  10. RequestidLecallBack

    To make use of the idle time, we can use requestIdleCallback to secretly fetch the necessary API data. If the data hasn't been fetched yet, we can then call the API to retrieve it. In this example, we use requestIdleCallback to fetch user data and store it. Later, when the user hovers over the avatar, we can directly display the introduction.

  11. window.requestIdleCallback()

    The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response. Functions are generally called in first-in-first-out order; however, callbacks which have a timeout specified may be ...

  12. Show HN: Speed up your site by running JavaScript when the browser is

    The README file presents it like an alternative to `requestIdleCallback`, while, in fact, it is a convenience wrapper around `requestIdleCallback`. It is a nice idea, but the description makes it confusing. ... Webkit is currently only used by Safari and maintained by Apple alone. (Also all iOS browsers have to use webkit which is why iOS ...

  13. requestIdleCallback()

    Queue a task on the queue associated with the idle-task task source, which performs the invoke idle callback timeout algorithm, passing handle and window as arguments. { {Window/requestIdleCallback ()}} only schedules a single callback, which will be executed during a single idle period.

  14. requestIdleCallback, Let the browser work for you!

    requestIdleCallback is a new api that lets the browser execute code when it is idle. In this case idle means that the browser is currently. at the end of a frame, has some free time and that the user is not interacting with the app in any way. requestIdleCallback will only fire. the function passed to it when these two requirements are met ...

  15. aFarkas/requestIdleCallback: A requestIdleCallback shim/polyfill

    requestIdleCallback can't be really polyfilled. Therefore requestIdleCallback basically includes a throttle like function, that uses some heuristics to detect a) long running frames and b) user input as also DOM mutations to adapt accordingly.requestIdleCallback also tries to get the time right after a frame commit. The deadline.timeRemaining() either starts with 7ms or with 22ms for the first ...

  16. Interactive guide on the requestIdleCallback() Web API

    The Web API requestIdleCallback() is undoubtedly one of the most underrated APIs in the web development ecosystem, offering the capability to schedule non-critical tasks for execution during idle periods in the browser.. Syntax. The requestIdleCallback() method is globally accessible in the browser context and requires one mandatory callback function to run during idle periods as the first ...

  17. requestIdleCallback Browser Compatibility On Safari

    requestidlecallback property shows Low browser compatibility on Safari browsers. Low browser compatibility means the requestidlecallback property is Not Supported by a majority of Safari browser versions.

  18. IdleDeadline

    IdleDeadline. The IdleDeadline interface is used as the data type of the input parameter to idle callbacks established by calling Window.requestIdleCallback(). It offers a method, timeRemaining(), which lets you determine how much longer the user agent estimates it will remain idle and a property, didTimeout, which lets you determine if your ...

  19. "requestIdleCallback"

    requestIdleCallback. API allowing the execution of JavaScript to be queued to run in idle browser time, either at the end of a frame or when the user is inactive. Also covers support for cancelIdleCallback. The API has similarities with requestAnimationFrame. 1 Can be enabled via the dom.requestIdleCallback.enabled flag.

  20. requestidlecallback-polyfill

    requestIdleCallback polyfill. Simple polyfill and d.ts for requestIdleCallback. From MDN:. The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response.

  21. Getting Started with requestIdleCallback: A Beginner's Guide

    To use requestIdleCallback, you simply need to pass your task function as a parameter to the API. The browser will then schedule the execution of your task during idle periods.