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

Determine the behavior when calling unobserve/disconnect method before the promise returned by observe method is settled #164

Open
wangw-1991 opened this issue Dec 16, 2022 · 20 comments

Comments

@wangw-1991
Copy link

wangw-1991 commented Dec 16, 2022

The following codes will cause the promise never resolve or reject in current implementation. It is more reasonable to reject these promises instead and the spec should give more clarity about this.

let promise = observer.observe('cpu');
observer.disconnect();

@rakuco
Copy link
Member

rakuco commented Dec 17, 2022

More generally speaking, PressureObserver.observe() returns a new Promise every time it is invoked, and PressureObserver.{disconnect,unobserve}() may be called while observe() is in the "in parallel" steps. It is not clear what should be done in this case as they should probably influence what happens to the unfulfilled promises.

@kenchris
Copy link
Contributor

Maybe this would work:

  • store pending observe promises
  • disconnect: reject all pending observe promises, but make sure that everything has been removed from "active observer list" - that should be fine with current spec text
  • unobserve: iterate over the pending promises and reject the ones matching the source. Remove from "active observer list" - might have been added, might not

Biggest issue I see if the "global task" as that will run when after JS has completed, including the sync disconnect/unobserve, so it will readd to the active observer list and activate the observation, so that code would probably have to check whether it's promise has been removed from the pending observer promises list and if so, don't do any work

@kenchris
Copy link
Contributor

Given it looks like we will remove the async permission stuff, this becomes a non-issue. But we should keep using promises in observe() so that we can add it back.

@rakuco
Copy link
Member

rakuco commented Dec 19, 2022

Given the current Blink implementation, I think this will still be an issue even if the permission bits are removed, as there are async steps involved in checking if source is a supported source type and when activating data delivery.

It could be possible to stop distinguishing between a successful async connection to the platform side (and maybe even drop the NotSupportedError exception related to checking for supported source types), but one would still have a window where the async connection is being established internally but disconnect/unobserve can still be called.

@kenchris
Copy link
Contributor

Given that we use an attribute for supported source types, we have not made that an async querying function, so we could do this check sync and it should not be an issue.

If we want to make that async in the future, it does become a problem yes.

@kenchris
Copy link
Contributor

If that is indeed async, how is the attribute implemented today then? Also the current activation was happening on the main tread (in the global task) so the promise resolve wasn't waiting on that, you just get the events when they are delivered

@kenchris
Copy link
Contributor

one would still have a window where the async connection is being established internally but disconnect/unobserve can still be called.

We haven't really spec'ed how that happens, and in the spec that also happens in the global task (main thread) so if we want to do that, we need to find out how to make these changes

@kenchris
Copy link
Contributor

@rakuco I did a PR to remove the permissions integration, but I can change it to keep the global task and instead do the activation in parallel. Then afterwards we could do the pendingPromises. If you think that is the way to go, tell me and I will prepare the PRs

@rakuco
Copy link
Member

rakuco commented Dec 19, 2022

If that is indeed async, how is the attribute implemented today then?

The supportedSources attribute just synchronously returns a hardcoded list at the moment. The observe() implementation queries the platform collector to know what source types are actually supported (e.g. calling observer('cpu') on Android would reject with a NotSupportedError).

Reading the spec again, it looks like supportedSources should also return what the platform collector supports though, which means the list can only be built asynchronously and there's a period where it won't have data to return.

Am I getting this correctly?

  • PressureSource contains all source types the spec recognizes.
  • What source types are actually supported depends on a combination of what the user agent implements and what the OS/hardware supports, which can only be determined asynchronously.
    • The result above is used by both the supportedSources attribute and the check in observe(). The latter can be done asynchronously, but the former cannot.

@kenchris
Copy link
Contributor

@arskama mentioned that the attribute getter returns only values supported by the spec and not necessarily the underlying hardware - I believe that is how it worked in some other specs, we can consider whether to change that or not.

@rakuco
Copy link
Member

rakuco commented Dec 19, 2022

@arskama mentioned that the attribute getter returns only values supported by the spec and not necessarily the underlying hardware

Values supported by the spec or by the implementation? If it's the former, then PressureSource suffices; if it's the latter, then it's either what the platform supports (which you only know asynchronously) or it's a third state that means "supported by the implementation but not necessarily by the platform" (in which case supportedSources does not necessarily return the same values as those used in the observe() check).

@kenchris
Copy link
Contributor

Basically what the browser supports on at least one of its platforms

@kenchris
Copy link
Contributor

Btw looking at those WebHID pending promises, I don't ever see them remove promises as they resolve. Looks like a mistake, or am I missing something?

@arskama
Copy link
Contributor

arskama commented Dec 19, 2022

https://wicg.github.io/compute-pressure/#platform-primitives
As written in the section mentioned above. The platform collector is the SW proxy to access the HW,which means that it can be all synchronously requested.

The question remaining is: How do we inform the user on the case where the HW doesn't support the platform collector requests? If observe is synchronous, there is no way to do it.

@arskama arskama closed this as completed Dec 19, 2022
@arskama arskama reopened this Dec 19, 2022
@kenchris
Copy link
Contributor

@Elchi3 I was wondering if you have any input on what supportedSources should expose. Right now it exposes the sources supported by the user agent (browser) but not necessarily supported on a platform (say Android) or by the hardware.

Should we change that and make it an async getter, or add a similar method with that behavior in addition to the attribute?

@Elchi3
Copy link

Elchi3 commented Apr 15, 2024

@Elchi3 I was wondering if you have any input on what supportedSources should expose. Right now it exposes the sources supported by the user agent (browser) but not necessarily supported on a platform (say Android) or by the hardware.

Good to know, I need to clarify this in the docs. So users will only find out if it is really supported in the current environment when calling observe()? In that case it seems supportedSources is merely a hint then?

https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver/supportedEntryTypes_static is the same thing for PerformanceObserver but I guess given the Perf APIs aren't depending on specific hardware, it is fine as a static property there.

Should we change that and make it an async getter, or add a similar method with that behavior in addition to the attribute?

Not sure if there is a standard way for it on the web platform but a method is used elsewhere (especially when it has to do with hardware support, see WebXR and WebGL).

https://developer.mozilla.org/en-US/docs/Web/API/CSS/supports_static
https://developer.mozilla.org/en-US/docs/Web/API/XRSystem/isSessionSupported
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getSupportedExtensions
https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getSupportedConstraints

@kenchris
Copy link
Contributor

Yeah so we could add a Promise<FrozenArray<string>> getSupportedSources() in place of the existing method

I think that would be more useful. @rakuco @arskama what do you think? How hard would this be @arskama ?

@kenchris
Copy link
Contributor

If we decide to do this, we can remove the existing API for now and if we don't make it, we can add this new method after shipping

@tomayac you feedback is also welcome

@arskama
Copy link
Contributor

arskama commented Apr 16, 2024

Before M125 release, I don't see it happening.

So if we want to provide the platform collector source list, then it s maybe better to remove it now and add it later when we have an implementation.

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

Successfully merging a pull request may close this issue.

5 participants