Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spec: Throttling Control - Script #4156

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

lflores-ms
Copy link
Contributor

Adds spec for Throttling Control (script) API.

specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
/// JavaScript tasks (`setTimeout` and `setInterval`), for the given
/// throttling category. A wake up interval is the amount of time that needs
/// to pass before the WebView2 Runtime checks for new timer tasks to run.
/// The default interval values are constants determined by the running
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified meaning of "determined by the WebView2 runtime".

specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
specs/ThrottlingControlScript.md Outdated Show resolved Hide resolved
/// throttling scenarios, or match the default background value (usually 1000
/// ms). The WebView2 Runtime will try to respect the preferred interval set
/// by the application, but the effective value will be constrained by
/// resource and platform limitations. Setting a value of `0` means no
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// resource and platform limitations. Setting a value of `0` means no
/// resource and platform limitations. Setting a value of `0` means a preference of no throttling be applied.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[pending]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.


[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2_21")]
{
UInt32 GetThrottlingIntervalPreference(CoreWebView2ThrottlingCategory category);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if instead of two methods on the CoreWebView2, we should make this four get/set properties on the CoreWebView2Settings.

Reading through your document it doesn't seem like its useful to have a method that takes this as an enum because the caller will always be explicitly changing the value of a specific category. In which case its probably easier to have individual properties for each category rather than a method where you choose the category.

And then the whole scenario seems very uncommon so rather than put this on the CoreWebView2 we can move it at least to the CoreWebView2Settings.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong opinion on whether to put these in CoreWebView2 or CoreWebView2Settings. Looking through our existing APIs, I see that there are properties in the settings object which are applied immediately, so I think we can use the same pattern here.

For enum vs methods. I don't have a strong preference either, but I'm not sure I understand the reasoning:

the caller will always be explicitly changing the value of a specific category

isn't this what we do for other APIs taking non-flags enum types?
Only thing is I think the enum makes it easier to find what the possible/configurable states are.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is what it would look like moving as properties to CoreWebView2Settings. Is this what you are suggesting?

namespace Microsoft.Web.WebView2.Core
{

    runtimeclass CoreWebView2Settings
    {
        // ...

        UInt32 ForegroundThrottlingIntervalPreference { get; set; }
        UInt32 BackgroundThrottlingIntervalPreference { get; set; }
        UInt32 IntensiveThrottlingIntervalPreference { get; set; }
        UInt32 IsolatedThrottlingIntervalPreference { get; set; }
    }

    runtimeclass CoreWebView2Frame
    {
        // ...
        
        Boolean ShouldUseIsolatedThrottling { get; set; };
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undecided on the name pattern though. I think we'd want them to show up together so maybe the pattern should be something like ThrottlingIntervalPreference<category> instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Giving them the same prefix does help group them although the name is less readable. Let's try that in the API review and see what they say

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just pushed the update moving to properties in settings object. Thanks!

@lflores-ms lflores-ms changed the base branch from spec/throttling-control-script to main November 15, 2023 23:56
@david-risney david-risney self-requested a review November 15, 2023 23:57
@lflores-ms lflores-ms added the API Proposal Review WebView2 API Proposal for review. label Nov 15, 2023

[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Settings9")]
{
UInt32 ThrottlingIntervalPreferenceForeground { get; set; };
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are all values in milliseconds, we should communicate that through the api. Either by the name of the api or by changing the type from UInt32 to something like TimeSpan.

Since you also ship a pure COM api in addition to the WinRT api, the TimeSpan type might not be available (I'm not sure).

Consider a name such as:

ThrottlingIntervalPreferenceInMillisecondsForeground 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For review discussion
I'm not aware of an available COM TimeSpan-equivalent type. I can think of the following options:

  • Keep current name pattern. There's likely precedent in CoreWebView2Notification.TimeStamp. Other TimeStamp APIs in Webview2 do put units in docs rather than the name: CoreWebView2Texture.TimeStamp (microseconds)
  • Use "Milliseconds" in the name. For discussion -- which position and whether to use "Milliseconds" or "InMilliseconds": PreferredThrottlingInterval<1>Foreground<2>

In either case, we can keep UInt32 in COM and expose as TimeSpan in .NET/WinRT.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InMilliseconds as a suffix

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COM: UInt32 InMilliseconds
.NET/WinRT TimeSpan no explicit suffix


Throttling Control APIs allow you to throttle JavaScript timers in scenarios
where the WebView2 control in your application needs to remain visible, but
consume less resources, for example, when the user is not interactive.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be helpful to elaborate a bit on what 'throttling' means in this case. If I set a throttling interval of 500ms, that means that timers will file at most once every 500ms - is that correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Especially because the Chromium docs call out two stages of throttling.

Stage 1: Timers run at normal speed for X seconds.
Stage 2: After X seconds, timers run at maximum speed Y.

It may not be clear whether this setting controls X or Y. I think it controls Y.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This paragraph is for API review only. Proper documentation for "throttling" meaning is in the API:

/// The preferred wake up interval (in milliseconds) to use for throttleable
/// JavaScript tasks (`setTimeout` and `setInterval`) [...]

/// A wake up interval is the amount of time that needs to pass before the
/// WebView2 Runtime checks for new timer tasks to run.

/// [...]
[propget] HRESULT ThrottlingIntervalPreferenceForeground([out, retval] UINT32* value);

I can use similar wording to the question above in the "For example" portion of the docs:

If I set a throttling interval of 500ms, that means that timers will file at most once every 500ms

/// For example, an application might use a foreground value of 30 ms for
/// moderate throttling scenarios, or match the default background value
/// (usually 1000 ms). **In this case, timers will file at most once every 30ms.**

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two stages of throttling from the referred document map as follows:

  • X -> ThrottlingIntervalPreferenceForeground
  • Y -> ThrottlingIntervalPreferenceBackground
  • there's a third state: ThrottlingIntervalPreferenceIntensive

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update docs. See discussion later on for changing name to be clearer.


## Throttle timers in hosted iframes

Throttling Control APIs allow you to throttle timers in specific frames within
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So every frame is either a 'regular' frame or an 'isolated' frame. Regular frames are controlled by ThrottlingIntervalPreferenceForeground/ThrottlingIntervalPreferenceBackground/ThrottlingIntervalPreferenceIntensive. Isolated frames are controlled by ThrottlingIntervalPreferenceIsolated.

Is there a reason why an isolated frame does not have Foreground/Background/Intensive properties? Or is that not an interesting scenario?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid question - Mostly not an interesting enough scenario to add the complexity. The primary use-case here is an app embedding 3rd party content and wanting to be able to independently limit the performance impact of it. Generally that's something like "low battery, throttle more" or "giving the frame N seconds to run some logic, throttle less".

The case where they'd want to put it in an isolated group while still managing foreground/background/intensive independently of the non-isolated timers would be a niche of a niche that even our most micromanage-y apps wouldn't want that granularity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this value takes precedence over the other values?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update sample to set isolated to at least match background to help demonstrate intended scenario / usage of isolated. Use Andy's comment to update the sample code.

Other names to consider:

  • Custom
  • Alternate
  • Override

Use the following:
PreferredOverrideTimerWakeIntervalInMilliseconds
UseOverrideTimerWakeInterval

```C#
namespace Microsoft.Web.WebView2.Core
{
runtimeclass CoreWebView2
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: class here should be CoreWebView2Settings, matching the COM API above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix!

/// background state with intensive throttling. Intensive throttling is a
/// substate of background state. For more details about intensive
/// throttling, see
/// [Intensive throttling of Javascript timer wake ups](https://chromestatus.com/feature/4718288976216064).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// [Intensive throttling of Javascript timer wake ups](https://chromestatus.com/feature/4718288976216064).
/// [Intensive throttling of JavaScript timer wake ups](https://chromestatus.com/feature/4718288976216064).

nit, capitalization on this instance of JavaScript

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is from the title of the linked document, so I'd lean towards keeping current casing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave as is.

consume less resources, for example, when the user is not interactive.

```c#
void OnNoUserInteraction()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like an event callback, but it is implied business logic of the sample app, not something rooted in the wv2 API surface, correct? Is there a prescribed way app should determine when the customer isn't "interactive"? (Or, is this concept already present in our samples elsewhere?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No prescribed way to implement detection logic, this is up to the app.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment to make it clear how the app would call this method.
A comment like 'the sample app calls this when ... but you might consider doing this in these cases ...'.
Follow up if we want to improve sample code to demonstrate how to actually do this - if we determine this is a common thing that will be helpful.

void OnNoUserInteraction()
{
// User is not interactive, keep webview visible but throttle timers to 500ms.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have precedence for wv2 intervals implicitly being milliseconds? I was going to propose including this in the property names, but realized we're aligning to JS' global functions that already do this. I didn't quickly find an existing webview2-related milliseconds property to check.

(Closest was bufferUsageReportingInterval, so maybe this is OK?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above on "Milliseconds": #4156 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See that comment for resolution.

/// The WebView2 Runtime will try to respect the preferred interval set by the
/// application, but the effective value will be constrained by resource and
/// platform limitations. Setting a value of `0` means a preference of no
/// throttling to be applied. The default value is a constant determined by
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we're missing a way to return to the WebView2 Runtime's default value. (In other words, there's no input for "I don't have a preference" for any of these properties?) I might expect preference=0 means I don't have any preference, but instead it means I prefer zero throttling.

Best case, the constant determined by the running version of the WebView2 Runtime is fixed, and my app can save it before overriding if I'd care about restoring it to 'default'?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// throttling to be applied. The default value is a constant determined by
/// throttling to be applied. The default value is determined by

I would simplify the text to say that the default value is determined by the runtime. Don't over-promise that it's a constant. It might be determined dynamically (one value if on AC, another if on battery, and another if in energy saver mode).

It seems that the only way to restore default behavior is to save the old value and set it back, and hope that there is no dynamic throttling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a known limitation and the only solution in current design is to save the value before changes. The intention behind this was to keep the API simpler, but if this is semantically meaningful, I can think of two options:

option 1

  • add toggle - e.g., CoreWebView2Settings.IsThrottlingEnabled
    • under current pattern, it would be 4 additional properties
    • alternatively, we can bring back the "throttling category" enum and use for both interval and toggle
  • make 0 reset to default

option 2

  • make 0 reset to default
  • make 1-4 mean off
    • due to architectural reasons, there's always an effective minimum 4 ms throttling (even when throttling is off)

none (current)

  • save value before changing, then restore

... or a reversal of option 1? (method for reset and keep 0 meaning off) I think option 1 is better than its reversal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer the 'simpler' option: save value before changing then restore - no new API changes.

[propput] HRESULT ThrottlingIntervalPreferenceIntensive([in] UINT32 value);

/// The preferred wake up interval (in milliseconds) to use for throttleable
/// JavaScript tasks (`setTimeout` and `setInterval`), in frames whose
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Interval Preference is unique among the four, in that it applies to frame hosted content instead of this WebView's direct content. Maybe worth differentiating e.g. ThrottlingIntervalPreferenceIsolatedFrames

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For review discussion
I agree and intent to update the name unless there's a different outcome during review.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

[propput] HRESULT ThrottlingIntervalPreferenceIntensive([in] UINT32 value);

/// The preferred wake up interval (in milliseconds) to use for throttleable
/// JavaScript tasks (`setTimeout` and `setInterval`), in frames whose
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All isolated Frames are subject to the same throttling preference? (I infer there's just little value in being able to throttle isolated frames to different intervals. Is that right?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, please make explicit in ref docs.


/// The preferred wake up interval (in milliseconds) to use for throttleable
/// JavaScript tasks (`setTimeout` and `setInterval`), in frames whose
/// `ShouldUseIsolatedThrottling` property is set to `TRUE`. This is a category
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternate design appears to be one uint32 property on CoreWebView2Frame, instead of a pair uint32 + Boolean properties to set the interval value and opt-in to applying it. Fewer properties to manage are often better. Was it discussed whether grouping this near the other IntervalPreferences is higher value in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative design options are limited by the Chromium architecture for throttling. While it's likely technically feasible to override individual frame intervals, a change like this would mean significantly more implementation complexity and risk. This was discussed during original design of the API, but we didn't identify a strong need for it, so we landed on a compromise of "isolated" interval + per-frame opt in.

If you have a scenario that strongly requires per-frame interval, please feel free to share in this review, or reach out to us through email.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing API surface better matches intended scenario. Leave as is.

[uuid(5b7d1b96-699b-44a2-b9f1-b8e88f9ac2be), object, pointer_default(unique)]
interface ICoreWebView2Frame6 : ICoreWebView2Frame5 {
/// Indicates whether the frame has been marked for isolated throttling by the
/// host app. When `TRUE`, the frame will receive the throttling interval set
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Should" suggests application preference. Are there any cases where the Boolean won't match whether IntervalPreferenceIsolated is being used? Documentation suggests this is fully IsUsingThrottlingIntervalPreferenceIsolated. (or a shorter name that is as definite.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename Should -> UseOverrideTimerWakeInterval

// Unthrottle background timers.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceBackground = 0;
// Effectively disable intensive throttling by overriding its timer interval.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceIntensive = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

void OnNoUserInteraction()
{
// User is not interactive, keep webview visible but throttle timers to 500ms.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are multiple types of throttling in Chromium. Timer throttling. Network throttling. Tab throttling. Extension throttling. CPU throttling. Authentication throttling.

From its name, it is not clear which of the many types of throttling this setting controls.

TimerThrottlingPreference(Foreground|Background|Intensive|Isolated)?

Or, for grammar,

(Foreground|Background|Intensive|Isolated)TimerThrottlingInterval?

Or if we really need to emphasize that this is a preference that may not be honored

Preferred(Foreground|Background|Intensive|Isolated)TimerThrottlingInterval?

Even the term "interval" is ambiguous. Is this the interval between throttlings? (No, it's the interval of the timer.)

Other parts of the documentation call this the "wake-up" interval.

Preferred(Foreground|Background|Intensive|Isolated)TimerWakeInterval?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Preferred(Foreground|Background|Intensive|Isolated)TimerWakeInterval(InMilliseconds) (InMilliseconds only for COM)


Throttling Control APIs allow you to throttle JavaScript timers in scenarios
where the WebView2 control in your application needs to remain visible, but
consume less resources, for example, when the user is not interactive.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Especially because the Chromium docs call out two stages of throttling.

Stage 1: Timers run at normal speed for X seconds.
Stage 2: After X seconds, timers run at maximum speed Y.

It may not be clear whether this setting controls X or Y. I think it controls Y.

webView.Visibility = System.Windows.Visibility.Hidden;
}

void DisableHiddenWebViewCore()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method name is confusing. The name says that it's disabling the hidden webview, but really it's showing the webview and setting new values.

Is this code trying to restore defaults? If so, it should save the previous values of the properties in SetupHiddenWebViewCore so that it can restore them here, rather than hard-coding what it believes to be the defaults.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name is sort of double negative. Better would be Hide/ShowWebView
If we're trying to undo previous changes back to previous values, we should be saving those values or showing how to do this properly.

/// The WebView2 Runtime will try to respect the preferred interval set by the
/// application, but the effective value will be constrained by resource and
/// platform limitations. Setting a value of `0` means a preference of no
/// throttling to be applied. The default value is a constant determined by
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// throttling to be applied. The default value is a constant determined by
/// throttling to be applied. The default value is determined by

I would simplify the text to say that the default value is determined by the runtime. Don't over-promise that it's a constant. It might be determined dynamically (one value if on AC, another if on battery, and another if in energy saver mode).

It seems that the only way to restore default behavior is to save the old value and set it back, and hope that there is no dynamic throttling.

[propget] HRESULT ShouldUseIsolatedThrottling([out, retval] BOOL* value);

/// Sets the `ShouldUseIsolatedThrottling` property.
[propput] HRESULT ShouldUseIsolatedThrottling([in] BOOL value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we add other types of throttling (network, etc.), will this flag also opt into isolated network throttling etc? Or is this only for timer throttling?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New name fixes this. See above.

void OnNoUserInteraction()
{
// User is not interactive, keep webview visible but throttle timers to 500ms.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the term "Foreground" here does not refer to Win32 "foreground" (receives keyboard input) but rather the Chromium concept of "foreground" which just means "programmatically visible". And even a programmatically visible that is completely occluded (so not visible to the end user) counts as "foreground".

Is this web-centric definition of "foreground" already established in WebView2-land?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a different kind of foreground defined in MDN: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API.

Please include definition and link in our docs.


// User is not interactive, keep webview visible but throttle timers to
// 500ms.
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceForeground(500));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When do these changes take effect? According to the documentation, all Settings properties take effect at the next top-level navigation, with two explicit exceptions that take effect immediately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Takes effect immediately. Will update the docs to state that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make explicit in our documentation.

webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceBackground = 0;
// Effectively disable intensive throttling by overriding its timer interval.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceIntensive = 0;
webView.Visibility = System.Windows.Visibility.Hidden;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want the throttling changes to take effect immediately, do we need to do a fake "navigate to self"? (Though that would destroy any page state, so maybe not?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n/a see above

{
if (args.Frame.Name == "isolated")
{
args.Frame.ShouldUseIsolatedThrottling = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does this setting take effect? Immediately? On next frame navigation? Is setting it in FrameCreated "soon enough"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Takes effect immediately. FrameCreated is the first chance to set the property as this is when we get the CoreWebView2Frame object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

/// (usually 1000 ms).
[propget] HRESULT ThrottlingIntervalPreferenceForeground([out, retval] UINT32* value);
/// Sets the `ThrottlingIntervalPreferenceForeground` property.
[propput] HRESULT ThrottlingIntervalPreferenceForeground([in] UINT32 value);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming of these properties should follow pattern of existing WebView2 APIs, using "Preferred" as prefix:

  • PreferredColorScheme
  • PreferredTrackingPreventionLevel

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above!

webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceBackground = 0;
// Effectively disable intensive throttling by overriding its timer interval.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceIntensive = 0;
webView.Visibility = System.Windows.Visibility.Hidden;
Copy link

@sschalek sschalek Nov 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the hosted JS know that it is invisible but there is a desire for it to still run in this state? Or would this info have to come through a different channel, or is the expectation that hosted code will always try to run if it can and won't itself, say, stop regular updates or communication with its backing service if the web platform says it's not visible?

Another way of putting it is, how is "visible as far as the web platform is concerned" differentiated from "host app has set the WV2 element to be visible" from "content is actually visible" both from the perspective of the host app calling these APIs and the hosted code having access to the web platform APIs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaScript context only has knowledge of "visible as far as the web platform is concerned" through Page Visibility API.

From the host app side, this is controlled by CoreWebView2Controller.IsVisible property. For WebView2 controls in .NET/WinRT, IsVisible property is controlled directly by the framework and tied to actual user visibility. The hosted JavaScript has no knowledge of this through its Web Platform API, but if needed, can be informed by the host through window.chrome.webview object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding explicit end to end description of how API fits into chromium/web platform feature to the ref docs and examples of how an end dev might use it

Comment on lines +191 to +192
/// foreground state. A WebView is in foreground state when its `IsVisible`
/// property is `TRUE`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this name mapping "visible" to "foreground" standard terminology? Otherwise, calling this ThrottlingIntervalPreferenceWhenVisible would be easier to understand

Also PreferredThrottlingInterval... rather than ThrottlingIntervalPreference....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

void OnUserInteraction()
{
// User is interactive again, unthrottle foreground timers.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading this sample, I though it was reverting OnNoUserInteraction, but it's actually putting it into a third mode.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update comment to make it clear if we're going to default value or not. (Confusion if this is supposed to be default value or 0). And consider updating sample code to show how to go to default value.


## Throttle timers in hosted iframes

Throttling Control APIs allow you to throttle timers in specific frames within
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this value takes precedence over the other values?

/// For example, an application might use a foreground value of 30 ms for
/// moderate throttling scenarios, or match the default background value
/// (usually 1000 ms).
[propget] HRESULT ThrottlingIntervalPreferenceForeground([out, retval] UINT32* value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typing guideline is Int32, unless it's truly necessary to support >2 billion

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix.

{
if (args.Frame.Name == "isolated")
{
args.Frame.ShouldUseIsolatedThrottling = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this affect nested frames? Or does the code need to handle hierarchy in the event handler?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great question!

Please update ref docs to clearly state it.

Please follow up with PM if we need this to be inherited or not. Alternatively, if grandchild frame event is coming soon then this is less interesting question to answer and not inherit is easier.


[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Settings9")]
{
UInt32 ThrottlingIntervalPreferenceForeground { get; set; };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InMilliseconds as a suffix


Throttling Control APIs allow you to throttle JavaScript timers in scenarios
where the WebView2 control in your application needs to remain visible, but
consume less resources, for example, when the user is not interactive.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update docs. See discussion later on for changing name to be clearer.

consume less resources, for example, when the user is not interactive.

```c#
void OnNoUserInteraction()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment to make it clear how the app would call this method.
A comment like 'the sample app calls this when ... but you might consider doing this in these cases ...'.
Follow up if we want to improve sample code to demonstrate how to actually do this - if we determine this is a common thing that will be helpful.


[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Settings9")]
{
UInt32 ThrottlingIntervalPreferenceForeground { get; set; };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COM: UInt32 InMilliseconds
.NET/WinRT TimeSpan no explicit suffix

void OnNoUserInteraction()
{
// User is not interactive, keep webview visible but throttle timers to 500ms.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See that comment for resolution.

void OnNoUserInteraction()
{
// User is not interactive, keep webview visible but throttle timers to 500ms.
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Preferred(Foreground|Background|Intensive|Isolated)TimerWakeInterval(InMilliseconds) (InMilliseconds only for COM)


/// The preferred wake up interval (in milliseconds) to use for throttleable
/// JavaScript tasks (`setTimeout` and `setInterval`), in frames whose
/// `ShouldUseIsolatedThrottling` property is set to `TRUE`. This is a category
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing API surface better matches intended scenario. Leave as is.


/// The preferred wake up interval (in milliseconds) to use for throttleable
/// JavaScript tasks (`setTimeout` and `setInterval`), in frames whose
/// `ShouldUseIsolatedThrottling` property is set to `TRUE`. This is a category
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update.

[uuid(5b7d1b96-699b-44a2-b9f1-b8e88f9ac2be), object, pointer_default(unique)]
interface ICoreWebView2Frame6 : ICoreWebView2Frame5 {
/// Indicates whether the frame has been marked for isolated throttling by the
/// host app. When `TRUE`, the frame will receive the throttling interval set
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename Should -> UseOverrideTimerWakeInterval

[propget] HRESULT ShouldUseIsolatedThrottling([out, retval] BOOL* value);

/// Sets the `ShouldUseIsolatedThrottling` property.
[propput] HRESULT ShouldUseIsolatedThrottling([in] BOOL value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New name fixes this. See above.

```C#
namespace Microsoft.Web.WebView2.Core
{
runtimeclass CoreWebView2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Proposal Review WebView2 API Proposal for review.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants