The Compute Pressure API provides a way for websites to react to changes in the CPU pressure of the target device, such that websites can trade off resources for an improved user experience.

Introduction

Modern applications often need to balance the trade offs and advantages of fully utilizing the system's computing resources, in order to provide a modern and delightful user experience.

As an example, many applications can render video effects with varying degrees of sophistication. These applications aim to provide the best user experience, while avoiding driving the user's device into a high pressure regime.

Utilization of [=processing units=] close to and often reaching 100% can lead to a bad user experience, as different tasks are fighting for the processing time. This can lead to slowless, which is especially noticeable with input delay. Further, a prolonged utilization close 100% can cause the [=processing units=] to heat up due to prolonged boosting, which can lead to throttling, resulting in an even worse user experience.

As a result of thermal limits, many smartphones, tablets and laptops can become uncomfortably hot to the touch. The fans in laptops and desktops can become so loud that they disrupt conversations or the users’ ability to focus.

In many cases, a device under high pressure appears to be unresponsive, as the operating system may fail to schedule the threads advancing the task that the user is waiting for. See also Use Cases.

A Note on Feature Detection

This section is non-normative.

Feature detection is an established web development best practice. Resources on the topic are plentiful on- and offline and the purpose of this section is not to discuss it further, but rather to put it in the context of detecting hardware-dependent features.

Consider the below feature detection examples:

Concepts

This specification defines the following concepts:

Processing Units

Computing devices consist of a multitude of different processing units such as the Central Processing Unit (CPU), the Graphics Processing Unit (GPU) and many specialized processing units. The latter are becoming popular such as ones designed to accelerate specific tasks like machine learning or computer vision.

Supported sources

The specification currently defines the supported source types as the Central [=Processing Unit=], also know as the CPU, but intents to support other [=source types=] such as GPU (Graphical [=Processing Unit=]) in future levels of this specification.

Sampling and Reporting Frequency

The sampling frequency for a [=platform collector=] is defined as a frequency at which the [=user agent=] obtains telemetry readings from the underlying platform.

The [=sampling frequency=] is equal to the [=requested sampling frequency=] if the [=user agent=] can support it.

The [=sampling frequency=] differs from the [=requested sampling frequency=] in the following cases:

It is recommended that the [=user agent=] limits the [=reporting frequency=] as outlined in [[[#rate-limiting-change-notifications]]].

The reporting frequency is the rate at which the {{PressureUpdateCallback}} will be queued as a [=task=] on the [=PressureObserver task source=] in case there is data to report.

The [=reporting frequency=] is not allowed to exceed the [=sampling frequency=].

In case the user didn't request a [=sampling frequency=], the [=sampling frequency=] is [=implementation-defined=].

Platform primitives

The [=platform collector=] refers to a platform interface, with which the [=user agent=] interacts to obtain the telemetry readings required by this specification.

A [=platform collector=] can be defined by the underlying platform (e.g. in a native telemetry framework) or by the [=user agent=], if it has a direct access to hardware counters.

A [=platform collector=] can support telemetry for different source types of computing devices defined by {{PressureSource}}, or there can be multiple [=platform collectors=].

From the implementation perspective [=platform collector=] can be treated as a software proxy for the corresponding hardware counters. It is possible to have multiple [=platform collector=] simultaneously interacting with the same underlying hardware if the underlying platform supports it.

In simple cases, a [=platform collector=] represents individual hardware counters, but if the provided counter readings are a product of data fusion performed in software, the [=platform collector=] represents the results of the data fusion process. This may happen in user space or in kernel space.

As collecting telemetry data often means polling hardware counters, it is not a free operation and thus, it should not happen if there are no one observing the data. See [[[#life-cycle]]] for more information.

A [=platform collector=] samples data at a specific frequency. A [=user agent=] may modify this frequency (if possible) for privacy reasons, or ignore and fuse certain readings.

Permissions and user prompts

The [[[PERMISSIONS]]] API provides a uniform way for websites to request permissions from users and query which permissions they have.

A user agent can per [=origin=] deny observation of a particular pressure [=source type=] by any [=implementation-defined=] reason, such as platform setting or user preference.

It is RECOMMENDED that a [=user agent=] show some form of unobtrusive notification that informs the user when a pressure observer is active, as well as provides the user with the means to block the ongoing operation, or simply dismiss the notification.

Permissions integration

The Compute Pressure API is a [=powerful feature=] which is identified by the name "`pressure`".

Internal Slot Definitions

Each [=global object=] has:

A registered observer consists of an observer (a {{PressureObserver}} object).

A constructed {{PressureObserver}} object has the following internal slots:

The [=user agent=] additionally has a max queued records integer, which is set to an [=implementation-defined=] value, greater than 0.

Pressure States

Pressure states represents the minimal set of useful states that allows websites to react to changes in compute and system pressure with minimal degration in quality or service, or user experience.

    enum PressureState { "nominal", "fair", "serious", "critical" };
  

The PressureState enum represents the [=pressure state=] with the following states:

Contributing Factors

Contributing factors represents the factors contributing to the system performance and current [=pressure state=]. In case the [=pressure state=] is nominal, the {{PressureRecord.factors}} will always an [=list/empty=] sequence.

    enum PressureFactor { "thermal", "power-supply" };
  

The PressureFactor enum represents the [=contributing factors=]:

Pressure Observer

The Compute Pressure API enables developers to understand the pressure of system resources such as the CPU.

The PressureUpdateCallback callback

    callback PressureUpdateCallback = undefined (
      sequence<PressureRecord> changes,
      PressureObserver observer
    );
  
This callback will be invoked when the [=pressure state=] changes.

The PressureObserver object

The {{PressureObserver}} can be used to observe changes in the [=pressure states=].

    enum PressureSource { "cpu" };

    [Exposed=(DedicatedWorker,SharedWorker,Window), SecureContext]
    interface PressureObserver {
      constructor(PressureUpdateCallback callback, optional PressureObserverOptions options = {});

      undefined observe(PressureSource source);
      undefined unobserve(PressureSource source);
      undefined disconnect();
      sequence<PressureRecord> takeRecords();

      [SameObject] static readonly attribute FrozenArray<PressureSource> supportedSources;

      [Exposed=Window] static Promise<PermissionState> requestPermission();
    };
  

The PressureObserver interface represents a {{PressureObserver}}.

The constructor() method

The `new` {{PressureObserver(callback, options)}} constructor steps are:

  1. Set |this:PressureObserver|.{{PressureObserver/[[Options]]}} to |options:PressureObserverOptions|.
  2. Set |this|.{{PressureObserver/[[Callback]]}} to |callback:PressureUpdateCallback|.

The observe() method

The {{PressureObserver/observe(source)}} method steps are:

  1. Let |permissionState:PermissionState| be the result of [=getting the current permission state=] with "`pressure`".
  2. If |permissionState| is not [=permission/granted=], throw {{NotAllowedError}}.
  3. If |source:PressureSource| is not a [=supported source type=], throw {{"NotSupportedError"}}.
  4. Let |relevantGlobal| be [=this=]'s [=relevant global object=].
  5. [=list/Append=] a new [=registered observer=] whose [=observer=] is [=this=] to |relevantGlobal|'s [=registered observer list=] for |source|.
  6. Activate [=data delivery=] of |source| data to |relevantGlobal|.

The unobserve() method

The {{PressureObserver/unobserve(source)}} method steps are:

  1. If |source:PressureSource| is not a [=supported source type=], throw {{"NotSupportedError"}}.
  2. [=list/Remove=] from |this|.{{PressureObserver/[[QueuedRecords]]}} all |records| associated with |source|.
  3. [=map/Remove=] |this|.{{PressureObserver/[[LastRecordMap]]}}[|source|].
  4. Let |relevantGlobal| be [=this=]'s [=relevant global object=].
  5. Remove any [=registered observer=] from |relevantGlobal|'s [=registered observer list=] for |source| for which [=this=] is the [=registered observer=].
  6. If the above [=registered observer list=] is [=list/empty=], deactivate [=data delivery=] of |source| data to |relevantGlobal|.

The disconnect() method

The {{PressureObserver/disconnect()}} method steps are:

  1. [=list/Empty=] |observer|.{{PressureObserver/[[QueuedRecords]]}}.
  2. [=map/Clear=] |this|.{{PressureObserver/[[LastRecordMap]]}}.
  3. Let |relevantGlobal| be [=this=]'s [=relevant global object=].
  4. Remove any [=registered observer=] from |relevantGlobal|'s' [=registered observer list=] for all supported [=source types=] for which [=this=] is the [=observer=].
  5. If the above [=registered observer list=] is [=list/empty=], deactivate [=data delivery=] of |source| data to |relevantGlobal|.

The takeRecords() method

The {{PressureObserver/takeRecords()}} method steps are:

  1. Let |records| be a [=list/clone=] of |observer|.{{PressureObserver/[[QueuedRecords]]}}.
  2. [=list/Empty=] |observer|.{{PressureObserver/[[QueuedRecords]]}}.
  3. Return |records|.

The supportedSources attribute

The {{PressureObserver/supportedSources}} attribute is informing on the [=supported source type=] by the [=platform collector=].

The {{PressureObserver/supportedSources}} getter steps are:

  1. Let |sources| be a [=list=] of |source:PressureSource|.
  2. Return |observer|'s frozen array of supported [=source types=].

The static requestPermission() method

The {{PressureObserver/requestPermission()}} static method steps are:

  1. If the [=relevant global object=] of [=this=] does not have [=transient activation=], return [=a new promise=] [=rejected=] with a {{NotAllowedError}}.
  2. Let |result:Promise| be [=a new promise=].
  3. Run these steps [=in parallel=]:
    1. Let |permissionState:PermissionState| be the result of [=requesting permission to use=] the [=powerful feature=] named "`pressure`".
    2. [=Queue a global task=] on the [=permissions task source=] with [=this=]'s [=relevant global object=] to [=resolve=] |result| with |permissionState|.
  4. Return |result|.

The PressureRecord dictionary

    dictionary PressureRecord {
      PressureSource source;
      PressureState state;
      sequence<PressureFactor> factors;
      DOMHighResTimeStamp time;
    };
  

The source attribute

The {{PressureRecord/source}} attribute represents the current [=source type=].

The state attribute

The {{PressureRecord/state}} attribute represents the current [=pressure state=].

The factors attribute

The {{PressureRecord/factor}} attribute represents a [=sequence=] of the current [=contributing factors=].

The time attribute

The {{PressureRecord/time}} attribute represents a {{DOMHighResTimeStamp}} that corresponds to the time the data was obtained from the system, relative to the [=time origin=] of the global object associated with the {{PressureObserver}} instance that generated the notification.

The PressureObserverOptions dictionary

    dictionary PressureObserverOptions {
      double frequency;
    };
  

The frequency member

The {{PressureObserverOptions/frequency}} member represents the requested sampling frequency in hertz.

Life-cycle and garbage collection

Each [=global object=] has a strong reference to [=registered observers=] in their [=registered observer list=] (one per source).

Processing Model

This section outlines the steps the user agent must take when implementing the specification.

Supporting algorithms

The passes privacy test steps given the argument |observer:PressureObserver|, are as follows:
  1. Let |relevantGlobal| be |observer|'s [=relevant global object=].
  2. If |relevantGlobal| is a {{Window}} object:
    1. If |relevantGlobal|'s [=associated document=] is not [=Document/fully active=], return false.
  3. If |relevantGlobal| is a {{WorkerGlobalScope}} object:
    1. If |relevantGlobal|'s relevant worker is not a active needed worker, return false.
  4. If |relevantGlobal|'s [=relevant settings object=]'s [=origin=] is [=same origin-domain=] with currently focused area's [=origin=], return true.
  5. [=list/For each=] |origin| in initiators of active Picture-in-Picture sessions:
      If |relevantGlobal|'s [=relevant settings object=]'s [=origin=] is [=same origin-domain=] with |origin|, return true.
  6. Otherwise, return false.
The passes frequency test steps given the argument |observer:PressureObserver|, |source:PressureSource| and |timestamp:DOMHighResTimeStamp|, are as follows:
  1. If |observer|.{{PressureObserver/[[LastRecordMap]]}}[|source|] does not [=map/exist=], return true.
  2. Let |record:PressureRecord| be |observer|.{{PressureObserver/[[LastRecordMap]]}}[|source|].
  3. Let |frequency| be |observer|.{{PressureObserver/[[Options]]}}.{{PressureObserverOptions/frequency}}.
  4. Let |timeDelta:DOMHighResTimeStamp| = |record|.{{PressureRecord/time}} - |timestamp|.
  5. If |timeDelta| > (1 / |frequency|), return true, otherwise return false.
The has change in data steps given the argument |observer:PressureObserver|, |state:PressureState| and |factors:sequence<PressureFactor>|, are as follows:
  1. If |observer|.{{PressureObserver/[[LastRecordMap]]}}[|source|] does not [=map/exist=], return true.
  2. Let |record:PressureRecord| be |observer|.{{PressureObserver/[[LastRecordMap]]}}[|source|].
  3. If |record|.{{PressureRecord/state}} is not equal to |state|, return true.
  4. If |record|.{{PressureRecord/factors}} and |factors| does not [=list/contain=] the same [=list/items=], return true.
  5. Return false.

Data delivery

[=Data delivery=] from a [=platform collector=] can be activate and deactivated in an [=implementation-defined=] manner per [=source type=] and [=global object=].

The data delivery steps that are run when an [=implementation-defined=] |data| sample of [=source type=] |source:PressureSource| is obtained from [=global object=] |relevantGlobal|'s [=platform collector=], are as follows:

  1. Let |source:PressureSource| be the [=source type=] of the |data| sample.
  2. Let |state:PressureState| be an [=implementation-defined=] state given |data| and |source|.
  3. Let |factors:sequence<PressureFactor>| be an [=implementation-defined=] [=sequence=] given |data| and |source|, potentially [=list/empty=].
  4. Let |timestamp:DOMHighResTimeStamp| be a timestamp representing the time the |data| was obtained from the |relevantGlobal|'s [=platform collector=].
  5. [=list/For each=] |observer:PressureObserver| in |relevantGlobal|'s [=registered observer list=] for |source|:
    1. If running [=passes privacy test=] with |observer| returns false, [=iteration/continue=].
    2. If running [=passes frequency test=] with |observer|, |source| and |timestamp| returns false, [=iteration/continue=].
    3. If running [=has change in data=] with |observer|, |state| and |factors| returns false, [=iteration/continue=].
    4. Run [=queue a record=] with |observer|, |source|, |state|, |factors| and |timestamp|.

Queue a PressureRecord

To queue a record given the arguments |observer:PressureObserver|, |source:PressureSource|, |state:PressureState|, |factors:sequence<PressureFactor>| and |timestamp:DOMHighResTimeStamp|, run these steps:

  1. Let |record:PressureRecord| be the result of running [=create a record=] with |source|, |state|, |factors| and |timestamp|.
  2. If [=list/size=] of |observer|.{{PressureObserver/[[QueuedRecords]]}} is greater than [=max queued records=], then [=list/remove=] the first [=list/item=].
  3. [=list/Append=] |record| to |observer|.{{PressureObserver/[[QueuedRecords]]}}.
  4. Set |observer|.{{PressureObserver/[[LastRecordMap]]}}[|source|] to |record|.
  5. [=Queue a pressure observer task=] with |observer|'s [=relevant global object=].

Create and populate a PressureRecord

To create a record given the arguments |source:PressureSource|, |state:PressureState|, |factors:sequence<PressureFactor>| and |timestamp:DOMHighResTimeStamp|, run these steps:

  1. Let |record:PressureRecord| be a new {{PressureRecord}} instance.
  2. Set |record|.|source:PressureSource| to |source|.
  3. Set |record|.|state:PressureState| be |state|.
  4. Set |record|.|factors:sequence<PressureFactor>| be |factors|.
  5. Set |record|.|time:DOMHighResTimeStamp| be |timestamp|.
  6. Return |record|.

Queue a Pressure Observer Task

The PressureObserver task source is a [=task source=] used for scheduling tasks to [[[#notify-observers]]].

To queue a pressure observer task given |relevantGlobal| as input, run these steps:

  1. If the |relevantGlobal|'s [=pressure observer task queued=] is true, then return.
  2. Set the |relevantGlobal|'s [=pressure observer task queued=] to true.
  3. [=Queue a global task=] on [=PressureObserver task source=] with |relevantGlobal| to [=notify pressure observers=].

Notify Pressure Observers

To notify pressure observers given |relevantGlobal| as input, run these steps:

  1. Set |relevantGlobal|'s [=pressure observer task queued=] to false.
  2. Let |notifySet| be a new [=set=] of all [=observers=] in |relevantGlobal|’s [=registered observer lists=].
  3. [=list/For each=] |observer:PressureObserver| of |notifySet|:
    1. Let |records| be a [=list/clone=] of |observer|.{{PressureObserver/[[QueuedRecords]]}}.
    2. [=list/Empty=] |observer|.{{PressureObserver/[[QueuedRecords]]}}.
    3. If |records| is not [=list/empty=], then invoke |observer|.{{PressureObserver/[[Callback]]}} with |records| and |observer|. If this throws an exception, catch it, and [=report the exception=].

Handling change of fully active

When a {{Document}} |document| is no longer [=Document/fully active=], deactivate [=data delivery=] of data of all [=supported source types=] to |document|'s [=relevant global object=].

When a worker with associated {{WorkerGlobalScope}} |relevantGlobal| is no longer an active needed workers, deactivate [=data delivery=] of data of all [=supported source types=] to |relevantGlobal|.

When a {{Document}} |document| becomes [=Document/fully active=], for each non-[=list/empty=] [=registered observer list=] associated the [=source type=] |source|, activate [=data delivery=] of |source| data to |document|'s [=relevant global object=].

When a worker with associated {{WorkerGlobalScope}} |relevantGlobal| becomes an active needed workers, for each non-[=list/empty=] [=registered observer list=] associated the [=source type=] |source|, activate [=data delivery=] of |source| data to |document|'s [=relevant global object=].

Handle unloading document and closing of workers

When a worker with associated {{WorkerGlobalScope}} |relevantGlobal|, once |relevantGlobal|'s [=WorkerGlobalScope/closing=] flag is set to true, deactivate [=data delivery=] for all [=supported source types=] to |relevantGlobal|.

As one of the [=unloading document cleanup steps=] given {{Document}} |document|, deactivate [=data delivery=] for all [=supported source types=] to |document|'s [=relevant global object=].

Security and privacy considerations

Please consult the Security and Privacy Self-Assessment based upon the [[[security-privacy-questionnaire]]].

Minimizing information exposure

Exposing hardware related events related to low -level details such as exact CPU utilization or frequency increases the risk of harming the user's privacy.

To mitigate this risk, no such low level details are exposed.

The subsections below describe the processing model. At a high level, the information exposed is reduced by the following steps:

  1. Rate-limiting - The user agent notifies the application of changes in the information it can learn. Change notifications are rate-limited.
  2. first-party context - The feature is only available in first-party contexts.

Rate-limiting change notifications

We propose exposing the pressure state via rate-limited change notifications. This aims to remove the ability to observe the precise time when a value transitions between two states.

More precisely, once the pressure observer is activated, it will be called once with initial values, and then be called when the values change. The subsequent calls will be rate-limited. When the callback is called, the most recent value is reported.

The specification will recommend a rate limit of at most one call per second for the active window, and one call per 10 seconds for all other windows. We will also recommend that the call timings are jittered across origins.

These measures benefit the user's privacy, by reducing the risk of identifying a device across multiple origins. The rate-limiting also benefits the user's security, by making it difficult to use this API for timing attacks. Last, rate-limiting change callbacks places an upper bound on the performance overhead of this API.

Rate limiting can be implemented in the user agent, but it might also be possible to simply change the polling frequency of the underlying hardware counters, if not accessed via a higher level framework.

No side-channels

It is possible to identify users across non-[=same origin=] sites if unique or very precise values can be accessed at the same time by sites not sharing origin.

If the same [=pressure state=] and timestamp is observed by two origins, that would be a good indication that the origin is used by the same user on the same machine. For this reason, the API limits reporting [=pressure state=] changes to one origin at the time.

A common way to do this, is only to report changes to the focused page, but one of the main users of this API are video conferencing sites. These sites want to make sure that the video streams and effects doesn't negatively affect the system and thus the conferencing experience - but there are two common cases where the site will usually not be focused:

  • The user is taking meeting notes and the site is in the background. Commonly the video stream is only visible via a picture-in-picture window.
  • The user is sharing an external application window such as a presentation, or sharing the whole screen, unusually with some UI indicating sharing is happening.
For this reason, the API considers these two cases to have higher priority than whether the site is focused.

First-party contexts

This API will only be available in frames served from the same origin as the top-level frame. This requirement is necessary for preserving the privacy benefits of the API's quantizing scheme.

The same-origin requirement above implies that the API is only available in first-party contexts.

Examples

As the Compute Pressure API is considered a [=powerful feature=], it requires user permission in order to be used.

You can check whether the user has already granted permission using the [[[Permissions]]] API, both from the [=browsing context/active window=] or from a worker.

    const { state } = await navigator.permissions.query({
      name: "pressure"
    });
    switch (state) {
      case "granted":
        startUsingFeature();
        break;
      case "prompt":
        showExplanationAndToogleToAllowFeature();
        break;
      case "denied":
        // Do nothing, user denies the site access to the feature
        break;
    }
  

Asking for permission has to happen in the [=browsing context/active window=] and can not be done from a worker, but the permission state is per [=origin=] and thus shared across [=browsing contexts=] and workers which are [=same origin=].

The below examples shows you how to ask for permission before using the feature.

    function handlePressureChange(records) {
      // do something with records.
    }

    button.onclick = async () => {
      const state = await PressureObserver.requestPermission();
      if (state === "granted") {
        const observer = new PressureObserver(handlePressureChange);
        observer.observe("cpu");
      }
    }
  

The callback is called with the observer it is invoked from. That allows to unobserve when certain conditions are met, or even to differenciate depending on who invoked it, if invoked by multiple observers or externally, say by `setTimeout()`.

    const samples = [];

    function pressureChange(records, observer) {
      for (const record of records) {
        samples.push(record.state);

        // We only want 20 samples.
        if (samples.length == 20) {
          observer.disconnect();
          return;
        }
      }
    }

    const observer = new PressureObserver(pressureChange);
    observer.observe("cpu");
  

In the following example we want to lower the number of concurrent video streams when the pressure becomes critical. For the sake of simplicity we only consider this one state.

As lowering the amount of streams might not result in exiting the critical state, or at least not immediately, we use a strategy where we lower one stream at the time every 30 seconds while still in the critical state.

We accomplish this by making sure the callback is called at least once every 30 seconds, or when the state actually changes. When the state changes we reset the interval timer.

    let timerId = -1;
    function pressureChange(records) {
      // Clear timer every time we are called, either by an actual state change,
      // or when called by setTimeout (see below).
      if (timerId > 0) {
        clearTimeout(timerId);
      }

      // When entering critical state, we want to recheck every 30sec if we are
      // still in critical state and if so, further reduce our concurrent streams.
      // For this reason we create a timer for 30 seconds that will call us back
      // with the last result in there were no change.
      const lastRecordArray = [records.at(records.length - 1)];
      timerId = setTimeout(pressureChange.bind(this, lastRecordArray), 30_000);

      for (const record of records) {
        if (record.state == "critical") {
          let streamsCount = getStreamsCount();
          setStreamsCount(streamsCount--);
        }
      }
    }

    const observer = new PressureObserver(pressureChange);
    observer.observe("cpu");
  

In the following example, we want to demonstrate the usage of {{PressureObserver/takeRecords()}}, by retrieving the remaining |records| accumulated since the the callback was last invoked.

It is recommended to do so before {{PressureObserver/disconnect()}}, otherwise {{PressureObserver/disconnect()}} will clear them and they will be lost forever.

For example, we might want to measure the pressure during a benchmarking workload, and thus want pressure telemetry for the exact duration of the workload. This means disconnecting all observers immediately when the task is completed, and manually requesting any pending pressure telemetry up to this point that might not have been delivered yet as part of the event loop cycle.

    function logWorkloadStatistics(records) {
      // do something with records.
    }

    const observer = new PressureObserver(logWorkloadStatistics);
    observer.observe("cpu");

    // Read pending state change records, otherwise they will be cleared
    // when we disconnect.
    const records = observer.takeRecords();
    logWorkloadStatistics(records);

    observer.disconnect();
  

In the following example, we show how to tell the observer to stop watching a specific |source:PressureSource| by invoking {{PressureObserver/unobserve()}} with |source|.

    const observer = new PressureObserver(records => { // do something with records. }));

    observer.observe("cpu");
    observer.observe("gpu");

    // Callback now gets called whenever the pressure state changes for 'cpu' or 'gpu'.

    observer.unobserve("gpu");

    // Callback now only gets called whenever the pressure state changes for 'cpu'.
  

In the following example, we show how to tell the observer to stop watching for any state changes by calling {{PressureObserver/disconnect()}}. Calling {{PressureObserver/disconnect()}} will stop observing all sources observed by previous {{PressureObserver/observe()}} calls.

Additionally it will clear all pending records collected since the last callback was invoked.

    const observer = new PressureObserver(records => { // do something with records. });
    observer.observe("cpu");
    observer.observe("gpu");

    // some time later...

    observer.disconnect();

    // records will be an empty array, because of the previous disconnect().
    const records = observer.takeRecords();
  

This specification defines conformance criteria for a single product: a user agent that implements the interfaces that it contains.

Acknowledgments

Many thanks for valuable feedback and advice from Anssi Kostiainen, Asaf Yaffe, Chen Xing, Evan Shrubsole, François Beaufort, Jan Gora, Jesse Barnes, Joshua Bell, Kamila Hasanbega, Matt Menke, Moh Haghighat, Nicolás Peña Moreno, Opal Voravootivat, Paul Jensen, Peter Djeu, Raphael Kubo da Costa, Reilly Grant, Ulan Degenbaev, Victor Miura, Wei Wang, and Zhenyao Mo