-
Notifications
You must be signed in to change notification settings - Fork 55
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
base: main
Are you sure you want to change the base?
Changes from all commits
03831fb
84a31c0
bb4deee
855667f
e6e1466
a477d20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,325 @@ | ||||||
Throttling Control - Script Throttling | ||||||
=== | ||||||
|
||||||
# Background | ||||||
Web content in WebView2 is generally subject to the same Web Platform | ||||||
restrictions as in the Microsoft Edge browser. However, some of the scenarios | ||||||
for WebView2 applications differ from the scenarios in the browser. For this | ||||||
reason, we're providing a set of APIs to fine-tune performance of scripts | ||||||
running in WebView2. These APIs allow WebView2 applications to achieve two | ||||||
things: | ||||||
|
||||||
* Customize script timers (`setTimeout` and `setInterval`) throttling under | ||||||
different page states (foreground, background, and background with intensive | ||||||
throttling) | ||||||
* Throttle script timers in select hosted iframes | ||||||
|
||||||
# Examples | ||||||
|
||||||
## Throttle timers in visible WebView | ||||||
|
||||||
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. | ||||||
|
||||||
```c# | ||||||
void OnNoUserInteraction() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?) There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||
{ | ||||||
// User is not interactive, keep webview visible but throttle timers to 500ms. | ||||||
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 500; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment above on "Milliseconds": #4156 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See that comment for resolution. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||
} | ||||||
|
||||||
void OnUserInteraction() | ||||||
{ | ||||||
// User is interactive again, unthrottle foreground timers. | ||||||
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceForeground = 0; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reading this sample, I though it was reverting There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||
} | ||||||
``` | ||||||
|
||||||
```cpp | ||||||
void ScenarioThrottlingControl::OnNoUserInteraction() | ||||||
{ | ||||||
wil::com_ptr<ICoreWebView2Settings> settings; | ||||||
m_webview->get_Settings(&settings); | ||||||
auto settings2 = settings.try_query<ICoreWebView2Settings9>(); | ||||||
CHECK_FEATURE_RETURN_EMPTY(settings2); | ||||||
|
||||||
// User is not interactive, keep webview visible but throttle timers to | ||||||
// 500ms. | ||||||
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceForeground(500)); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Takes effect immediately. Will update the docs to state that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make explicit in our documentation. |
||||||
} | ||||||
|
||||||
void ScenarioThrottlingControl::OnUserInteraction() | ||||||
{ | ||||||
wil::com_ptr<ICoreWebView2Settings> settings; | ||||||
m_webview->get_Settings(&settings); | ||||||
auto settings2 = settings.try_query<ICoreWebView2Settings9>(); | ||||||
CHECK_FEATURE_RETURN_EMPTY(settings2); | ||||||
|
||||||
// User is interactive again, unthrottle foreground timers. | ||||||
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceForeground(0)); | ||||||
} | ||||||
``` | ||||||
|
||||||
## Unthrottle timers in hidden WebView | ||||||
|
||||||
Throttling Control APIs allow you to set a custom throttling interval for timers | ||||||
on hidden WebViews. For example, if there's logic in your app that runs in | ||||||
JavaScript but doesn't need to render content, you can keep the WebView hidden | ||||||
and unthrottle its timers. | ||||||
|
||||||
```C# | ||||||
void SetupHiddenWebViewCore() | ||||||
{ | ||||||
// This WebView2 will remain hidden but needs to keep running timers. | ||||||
// Unthrottle background timers. | ||||||
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceBackground = 0; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Include declarations of webView or comments to make it clear what the type of webView is (confusion over CoreWebView2, WebView2, CoreWebView2Controller). Or add a member coreWebView2_ so we don't have to deal with UI framework elements. |
||||||
// Effectively disable intensive throttling by overriding its timer interval. | ||||||
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceIntensive = 0; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noting that "intensive" is the public name Chromium has given to this feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. |
||||||
webView.Visibility = System.Windows.Visibility.Hidden; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. n/a see above There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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, There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||||||
} | ||||||
|
||||||
void DisableHiddenWebViewCore() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Name is sort of double negative. Better would be Hide/ShowWebView |
||||||
{ | ||||||
webView.Visibility = System.Windows.Visibility.Visible; | ||||||
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceBackground = 1000; | ||||||
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceIntensive = 60000; | ||||||
} | ||||||
``` | ||||||
|
||||||
```cpp | ||||||
void ScenarioThrottlingControl::SetupHiddenWebViewCore() | ||||||
{ | ||||||
wil::com_ptr<ICoreWebView2Settings> settings; | ||||||
m_webview->get_Settings(&settings); | ||||||
auto settings2 = settings.try_query<ICoreWebView2Settings9>(); | ||||||
CHECK_FEATURE_RETURN_EMPTY(settings2); | ||||||
|
||||||
// This WebView2 will remain hidden but needs to keep running timers. | ||||||
// Unthrottle background timers. | ||||||
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceBackground(0)); | ||||||
// Effectively disable intensive throttling by overriding its timer interval. | ||||||
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceIntensive(0)); | ||||||
|
||||||
CHECK_FAILURE(m_appWindow->GetWebViewController()->put_IsVisible(FALSE)); | ||||||
} | ||||||
|
||||||
void ScenarioThrottlingControl::DisableHiddenWebViewCore() | ||||||
{ | ||||||
CHECK_FAILURE(m_appWindow->GetWebViewController()->put_IsVisible(TRUE)); | ||||||
|
||||||
wil::com_ptr<ICoreWebView2Settings> settings; | ||||||
m_webview->get_Settings(&settings); | ||||||
auto settings2 = settings.try_query<ICoreWebView2Settings9>(); | ||||||
CHECK_FEATURE_RETURN_EMPTY(settings2); | ||||||
|
||||||
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceBackground(1000)); | ||||||
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceIntensive(60000)); | ||||||
} | ||||||
``` | ||||||
|
||||||
## Throttle timers in hosted iframes | ||||||
|
||||||
Throttling Control APIs allow you to throttle timers in specific frames within | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 Is there a reason why an isolated frame does not have Foreground/Background/Intensive properties? Or is that not an interesting scenario? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this value takes precedence over the other values? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
Use the following: |
||||||
the WebView2 control. For example, if your application uses iframes to host 3rd | ||||||
party content, you can select and mark these frames to be throttled separately | ||||||
from the main frame and other regular, unmarked frames. | ||||||
|
||||||
```C# | ||||||
void SetupIsolatedFramesHandler() | ||||||
{ | ||||||
// You can use the frame properties to determine whether it should be | ||||||
// marked to be throttled separately from main frame. | ||||||
webView.CoreWebView2.FrameCreated += (sender, args) => | ||||||
{ | ||||||
if (args.Frame.Name == "isolated") | ||||||
{ | ||||||
args.Frame.ShouldUseIsolatedThrottling = true; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Takes effect immediately. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see above There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||
} | ||||||
}; | ||||||
|
||||||
webView.CoreWebView2.Settings.ThrottlingIntervalPreferenceIsolated = 500; | ||||||
} | ||||||
``` | ||||||
|
||||||
```cpp | ||||||
void ScenarioThrottlingControl::SetupIsolatedFramesHandler() | ||||||
{ | ||||||
auto webview4 = m_webview.try_query<ICoreWebView2_4>(); | ||||||
CHECK_FEATURE_RETURN_EMPTY(webview4); | ||||||
|
||||||
// You can use the frame properties to determine whether it should be | ||||||
// marked to be throttled separately from main frame. | ||||||
CHECK_FAILURE(webview4->add_FrameCreated( | ||||||
Callback<ICoreWebView2FrameCreatedEventHandler>( | ||||||
[this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT | ||||||
{ | ||||||
wil::com_ptr<ICoreWebView2Frame> webviewFrame; | ||||||
CHECK_FAILURE(args->get_Frame(&webviewFrame)); | ||||||
|
||||||
auto webviewFrame6 = | ||||||
webviewFrame.try_query<ICoreWebView2Frame6>(); | ||||||
CHECK_FEATURE_RETURN_HRESULT(webviewFrame6); | ||||||
|
||||||
wil::unique_cotaskmem_string name; | ||||||
CHECK_FAILURE(webviewFrame->get_Name(&name)); | ||||||
if (wcscmp(name.get(), L"isolated") == 0) | ||||||
{ | ||||||
CHECK_FAILURE(webviewFrame6->put_ShouldUseIsolatedThrottling(TRUE)); | ||||||
} | ||||||
|
||||||
return S_OK; | ||||||
}) | ||||||
.Get(), | ||||||
&m_frameCreatedToken)); | ||||||
|
||||||
wil::com_ptr<ICoreWebView2Settings> settings; | ||||||
m_webview->get_Settings(&settings); | ||||||
auto settings2 = settings.try_query<ICoreWebView2Settings9>(); | ||||||
CHECK_FAILURE(settings2->put_ThrottlingIntervalPreferenceIsolated(500)); | ||||||
} | ||||||
``` | ||||||
|
||||||
# API Details | ||||||
```cpp | ||||||
/// A continuation of the `ICoreWebView2Settings` interface to support | ||||||
/// ThrottlingPreference. | ||||||
[uuid(00f1b5fb-91ed-4722-9404-e0f8fd1e6b0a), object, pointer_default(unique)] | ||||||
interface ICoreWebView2Settings9 : ICoreWebView2Settings8 { | ||||||
/// The preferred wake up interval (in milliseconds) to use for throttleable | ||||||
/// JavaScript tasks (`setTimeout` and `setInterval`), when the WebView is in | ||||||
/// foreground state. A WebView is in foreground state when its `IsVisible` | ||||||
/// property is `TRUE`. | ||||||
Comment on lines
+191
to
+192
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this name mapping "visible" to "foreground" standard terminology? Otherwise, calling this Also There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. |
||||||
/// | ||||||
/// 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 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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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'? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
option 2
none (current)
... or a reversal of option 1? (method for reset and keep 0 meaning off) I think option 1 is better than its reversal. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||||||
/// the running version of the WebView2 Runtime. | ||||||
/// | ||||||
/// 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); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please fix. |
||||||
/// Sets the `ThrottlingIntervalPreferenceForeground` property. | ||||||
[propput] HRESULT ThrottlingIntervalPreferenceForeground([in] UINT32 value); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above! |
||||||
|
||||||
/// The preferred wake up interval (in milliseconds) to use for throttleable | ||||||
/// JavaScript tasks (`setTimeout` and `setInterval`), when the WebView is in | ||||||
/// background state, with no intensive throttling. A WebView is in background | ||||||
/// state when its `IsVisible` property is `FALSE`. 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). | ||||||
/// | ||||||
/// 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 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 | ||||||
/// the running version of the WebView2 Runtime. All other background state | ||||||
/// policies (including intensive throttling) are effective independently of | ||||||
/// this setting. | ||||||
/// | ||||||
/// For example, an application might use a background value of 100 ms to | ||||||
/// relax the default background value (usually 1000 ms). | ||||||
[propget] HRESULT ThrottlingIntervalPreferenceBackground([out, retval] UINT32* value); | ||||||
/// Sets the `ThrottlingIntervalPreferenceBackground` property. | ||||||
[propput] HRESULT ThrottlingIntervalPreferenceBackground([in] UINT32 value); | ||||||
|
||||||
/// The preferred wake up interval (in milliseconds) to use for throttleable | ||||||
/// JavaScript tasks (`setTimeout` and `setInterval`), when the WebView is in | ||||||
/// 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). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit, capitalization on this instance of JavaScript There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leave as is. |
||||||
/// | ||||||
/// 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 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 | ||||||
/// the running version of the WebView2 Runtime. | ||||||
[propget] HRESULT ThrottlingIntervalPreferenceIntensive([out, retval] UINT32* value); | ||||||
/// Sets the `ThrottlingIntervalPreferenceIntensive` property. | ||||||
[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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For review discussion There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, please make explicit in ref docs. |
||||||
/// `ShouldUseIsolatedThrottling` property is set to `TRUE`. This is a category | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Existing API surface better matches intended scenario. Leave as is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add for emphasis
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please update. |
||||||
/// specific to WebView2 with no corresponding state in the Chromium tab state | ||||||
/// model. | ||||||
/// | ||||||
/// 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 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 | ||||||
/// the running version of the WebView2 Runtime. | ||||||
/// | ||||||
/// For example, an application might use an isolated throttling value of 30 | ||||||
/// ms to reduce resource consumption from third party frames in the WebView. | ||||||
[propget] HRESULT ThrottlingIntervalPreferenceIsolated([out, retval] UINT32* value); | ||||||
/// Sets the `ThrottlingIntervalPreferenceIsolated` property. | ||||||
[propput] HRESULT ThrottlingIntervalPreferenceIsolated([in] UINT32 value); | ||||||
} | ||||||
|
||||||
/// A continuation of the `ICoreWebView2Frame` interface to support | ||||||
/// ShouldUseIsolatedThrottling property. | ||||||
[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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename Should -> UseOverrideTimerWakeInterval |
||||||
/// by `ThrottlingIntervalPreferenceIsolated`. When `FALSE`, and for main | ||||||
/// frame, throttling interval will be determined by page state and the | ||||||
/// interval through their corresponding properties in the | ||||||
/// `CoreWebView2Settings` object. Defaults to `FALSE` unless set otherwise. | ||||||
[propget] HRESULT ShouldUseIsolatedThrottling([out, retval] BOOL* value); | ||||||
|
||||||
/// Sets the `ShouldUseIsolatedThrottling` property. | ||||||
[propput] HRESULT ShouldUseIsolatedThrottling([in] BOOL value); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: class here should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please fix! |
||||||
{ | ||||||
// ... | ||||||
|
||||||
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Settings9")] | ||||||
{ | ||||||
UInt32 ThrottlingIntervalPreferenceForeground { get; set; }; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For review discussion
In either case, we can keep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. COM: UInt32 InMilliseconds |
||||||
|
||||||
UInt32 ThrottlingIntervalPreferenceBackground { get; set; }; | ||||||
|
||||||
UInt32 ThrottlingIntervalPreferenceIntensive { get; set; }; | ||||||
|
||||||
UInt32 ThrottlingIntervalPreferenceIsolated { get; set; }; | ||||||
} | ||||||
} | ||||||
|
||||||
runtimeclass CoreWebView2Frame | ||||||
{ | ||||||
// ... | ||||||
|
||||||
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Frame6")] | ||||||
{ | ||||||
Boolean ShouldUseIsolatedThrottling { get; set; }; | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
``` | ||||||
|
||||||
# Appendix |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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:
I can use similar wording to the question above in the "For example" portion of the docs:
There was a problem hiding this comment.
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:
ThrottlingIntervalPreferenceForeground
ThrottlingIntervalPreferenceBackground
ThrottlingIntervalPreferenceIntensive
There was a problem hiding this comment.
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.