Giter Club home page Giter Club logo

Comments (32)

jernoble avatar jernoble commented on August 19, 2024 2

@rebeccahughes

From a browser perspective there may be a lot of state across many different components that goes into determining whether a page can play or not.

Sure, but that argument can be made for almost any API, especially all those on HTMLMediaElement. I don't think it's unreasonable that a browser engine should be able to answer "what's the current time" synchronously, though that could require cross-component calls to answer accurately. Same for "buffered", "seekable", etc. So what is it that makes "autoplayPolicy" different?

Promises make features that are inherently asynchronous nicer; IMHO, I don't think they should be used to make inherently synchronous features "future proof" for browser implementers.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024 2

It's the UA's job to manage complexity. "It's complex" is not a good enough reason to require web developers to absorb that complexity.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024 2

No, there's nothing about this API that's inherently asynchronous. Your implementation may be designed in such a way that makes the implementation asynchronous, but that is not inherent to the API. That exact same argument could be made about any API. Making this API a Promise pushes your own internal design decisions upon your clients, and that's bad API design.

from autoplay.

cpearce avatar cpearce commented on August 19, 2024

The ServiceWorkerContainer.ready is different in that it resolves to a ServiceWorkerRegistration object, and there is only one instance of this object per ServiceWorkerContainer. The fields of the ServiceWorkerRegistration instance can change, but the instance of that object associated with the ServiceWorkerContainer doesn't change.

Whereas the values returned by Document.autoplayPolicy can change over time. So once the promise has settled on a particular allowed/not-allowed result, what happens when that changes and the document becomes allowed to play? Clear Document.autoplayPolicy and assign to it a new promise resolved to the new value? That might have surprising results, for example if the only reference to some other object was held by closures in that promise chain, that thing would be GC'd.

If this must be async, it makes more sense for this to be:

partial interface Document {
    [NewObject] Promise<AutoplayPolicy> autoplayPolicy();
}

Then it's more obvious that the calling script is the only thing keeping the promise/chain alive.

from autoplay.

cpearce avatar cpearce commented on August 19, 2024

The next obvious question is why does this need to be async? :)

The description in issue 1 is:

document.autoplayPolicy returns a enum string that can change overtime based on user session activity

The fact this says "returns" to me implies it was intended to be synchronous.

Being synchronous makes sense, as this is basically just looking up a bit set on the relevant document object.

from autoplay.

 avatar commented on August 19, 2024

The next obvious question is why does this need to be async? :)

From a browser perspective there may be a lot of state across many different components that goes into determining whether a page can play or not. It would be nice to not have to keep all this state in sync in the renderer when we do not necessarily need to. i.e. when a user calls autoplayPolicy() we can go and fetch all the data and make a decision. It would also be somewhat future proof if browsers wish to change and experiment with their implementations in the future.

If we are using a promise we probably should forward any user gesture state so things like this would work:

document.autoplayPolicy().then((policy) => {
  if (policy == 'allowed') video.play();
});

from autoplay.

mounirlamouri avatar mounirlamouri commented on August 19, 2024

Making the feature synchronous requires a lot of added complexity that we have to deal with because of some ways people currently detect autoplay (v.play(); if (v.paused)). In Chrome and I expect Firefox and Safari, we need to look at a few components to know whether autoplay is allowed and today, we have to pass this information on navigation to make sure it's available ASAP. This is really not ideal.

Worth nothing that await makes using promises much simpler for web developers. They can just do:

let policy = await document.autoplayPolicy();

And whether this should be an attribute or a function, it doesn't really matter much to me.

from autoplay.

mounirlamouri avatar mounirlamouri commented on August 19, 2024

I agree with this when it's just "hard to do" but here the complexity is architectural and I guess it's more of a cost/limitations. Synchronous APIs should be easily available synchronously. This is definitely not the case for autoplay and there are a lot of cases where answering this question should take more than a quick query. I'm actually very surprised Mozilla would support the API being synchronous as they are considering backing this with some permissions and the Permissions API is fully designed asynchronously. I would expect the permissions to be accessed at the browser process level which means that the renderer process would either need to be aware of the permission at its creation and for each navigation or the API would do a synchronous call to the browser process.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

@mounirlamouri

I would expect the permissions to be accessed at the browser process level which means that the renderer process would either need to be aware of the permission at its creation and for each navigation or the API would do a synchronous call to the browser process.

So, it's inherently synchronous because it's known before the page is ever loaded. Promises should be used for inherently /asynchronous/ APIs, and not merely where they're convenient for a specific UAs process model.

from autoplay.

mounirlamouri avatar mounirlamouri commented on August 19, 2024

The TAG recommendations seem to be aligned with my approach here: https://w3ctag.github.io/design-principles/#promises

In particular, I think the points around disk access and different process apply here. Today, we have to load everything from disk on startup and we would rather have this done lazily which we can only do with an async API. Same for the process: we have to pass the information to the child process at creation because the API is synchronous and could be avoided with an async API.

from autoplay.

mounirlamouri avatar mounirlamouri commented on August 19, 2024

My understanding from the TAG's recommendations are exactly that API should be asynchronous unless we are fairly certain that:

  • they will never need a permission prompt;
  • they will never need disk access;
  • they will never need network access;
  • they will never need to run across processes.

My understanding is that today Safari, Chrome and Firefox are doing cross process operations with disk access to answer the question the API is asking. Our design allows us to resolve this synchronously but I don't think we should put this constraints to every browser that will have to implement this API.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

Your understanding is incorrect w.r.t. Safari. The TAG recommendations should apply if the API requires disk access, not if there is any possible implementation which may want to lazily read from disk. And that's ignoring the weirdness of having a Promise backed property change state dynamically after it has resolved.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

Additionally, the "implementations may need to consider information that might be stored on disk in order to compute the result" recommendation doesn't apply here. There is no input to this API which a browser would need to read data from disk to compute. All the inputs to this property are known before the page is even loaded.

from autoplay.

mounirlamouri avatar mounirlamouri commented on August 19, 2024

Checking the document's URL against a list of allowed website (MEI for Chrome, permission for Firefox) is a disk access even if there is no input, right?

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

Sure, everything is on disk at some point. And if you take this argument to it's maximal conclusions, there is no API that should not be made a Promise because there exists some potential UA that may want to lazily load things from disk.

from autoplay.

 avatar commented on August 19, 2024

The TAG recommendations also cover cross thread and cross process implementations which would also be the case here since checking the list will likely require a process hop.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

Again, that is an implementation choice, and not intrinsic to the API. The Promise requirements should be reserved for things that require a process hop, like communication between Workers, and not for implementation optimization decisions.

from autoplay.

 avatar commented on August 19, 2024

Yes, although the recommendations specify that if an implementation may want to go down that route then the API should be async. The section in particular is talking about implementations, rather than whether a cross-thread/process hop is part of the spec.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

And as I said earlier, the logical conclusion of that argument is that every new API has to be a Promise. Therefore, that interpretation must be wrong, as it would make the recommendation meaningless.

If instead of looking at the Promise guidelines, you look at the actual Writing Promise-Using Specifications document, you see this recommendation under "3. When Not To Use Promises":

3.1. Recurring Events
Any event that can occur more than once is not a good candidate for the "one and done" model of promises. There is no single asynchronous operation for the promise to represent, but instead a series of events. Conventional EventTarget usage is just fine here.

Because the value of this property will logically change over time, a Promise is the wrong thing to use.

from autoplay.

 avatar commented on August 19, 2024

I am not sure that the "recurring events" section would apply here because we are exposing state rather than an event. Maybe if it was something like an autoplayPolicyChanged event then that section would be applicable.

It's also not a series of events, it is a single async operation and also the recommendation here is to use EventTarget which we are not using.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

Yes, that's another problem with the proposal: there is no way to know when the property changed, as there is no event defined that fires when the value resolved by the Promise is no longer valid.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

To expand on this last point: the only reason for the property to be a Promise is due to a browser-specific optimization, and not because it is inherently asynchronous, and because the property will change over time, it should have an associated event to notify clients that the property changed, but because it is a recurring event and not a one-shot, that would require the property to not be a Promise in the first place.

from autoplay.

 avatar commented on August 19, 2024

I believe the "2.3. More General State Transitions" applies here and this goes back to the original suggestion of having an attribute that returns a Promise:

partial interface Document {
  readonly attribute Promise<AutoplayPolicy> autoplayPolicy;
};

This is already used in other places like the "Font Face" interface which uses a loaded attribute that returns a Promise.

From an autoplay perspective here we could check the state asynchronously when the getter is called on the attribute and then resolve the promise.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

@rebeccahughes

This is already used in other places like the "Font Face" interface which uses a loaded attribute that returns a Promise.

loaded is a one-shot change. The state will never change from "loaded: true" to "loaded: false".

From an autoplay perspective here we could check the state asynchronously when the getter is called on the attribute and then resolve the promise.

That would require a new Promise to be returned from the object for every time the property is accessed, breaking the this.property === this.property principle.

EDIT: I misread the source document, you absolutely can move to the unloaded state. Mea culpa.

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

Updated my previous comment. I still don't believe this is an appropriate example, because in the case of Image unloading, that property change is due to an explicit action on the image element by the client, and this property could happen at any time (so the client has no option other than to poll to detect a state transition.)

from autoplay.

jernoble avatar jernoble commented on August 19, 2024

Also, note the caveat in that section:

To close, we must caution against over-using this pattern. Not every state transition needs a corresponding promise-property. Indicators that it might be useful include:
Authors are almost always interested in the next instance of that state transition, and rarely need recurring notification every time it occurs. For example, rarely do authors care to know every time an image element is reloaded; usually they simply care about the initial load of the image, or possibly the next one that occurs after resetting its src.
Authors are often interested in reacting to transitions that have already occurred. For example, authors often want to run some code once an image is loaded; if the image is already loaded, they want to run the code as soon as possible.

Neither of those applies here.

from autoplay.

MattiasBuelens avatar MattiasBuelens commented on August 19, 2024

Hi, I'm a software architect working at an online video player company. We've been dealing with autoplay policies in our web player, so I've been following these discussions a bit on the sidelines. 🙂

I also believe a promise property isn't the right approach here. For example, I don't see how this could handle changes in the autoplay policy. The page could start out with an "allowed" policy, but could later on transition to "allowed-muted" or "disallowed" when the user changes their (site-specific) preferences. How could a script detect this change?

  • If the promise is one-shot and resolves when the policy is loaded for the first time, the script would only ever see "allowed". It would have no way to know that the policy changed later on.
  • If the promise is replaced at every state transition, you'd need to write some very awkward code to deal with it:
let currentPolicy;
function updatePolicy(policy) {
  // Do something with the new autoplay policy...
  currentPolicy = policy;
  // Attach a handler to the new promise, in case the policy changes later
  document.autoplayPolicy.then(updatePolicy);
}
// Wait for the first change
// But what if it never changes, or it already changed but we "missed" it?
document.autoplayPolicy.then(updatePolicy);

I agree with @jernoble that a string property autoplayPolicy with a corresponding autoplaypolicychange event would be more appropriate. The code becomes much more natural:

let currentPolicy = document.autoplayPolicy;
document.addEventListener('autoplaypolicychange', () => {
  currentPolicy = document.autoplayPolicy;
  // Do something with the new autoplay policy...
});

If the user agent does not yet know the correct autoplay policy on document load, it could initialize the property to some sane default (e.g. "disallowed") and update it later by dispatching an autoplaypolicychange event. It could even use the act of attaching an event listener on that particular event as an indication whether the page is interested in the policy at all, and only load the policy when such an event listener is attached. This is a bit like how setting MessagePort.onmessage for the first time calls start(), since it indicates that the script is now ready to receive messages on this port.

from autoplay.

 avatar commented on August 19, 2024

@MattiasBuelens - Setting to disallowed by default would potentially block any HTML media elements with the autoplay attribute. We would then have to start them playing when we update the autoplay state which is something we should avoid (e.g. clicking a page would start the video playing).

I'm not sure we should be taking away autoplay from a document once it has been granted e.g. disabling autoplay on a site won't have an effect if the site is already autoplaying.

In which case we would always be progressing towards an allowed state. document.autoplayPolicy should only be used for adjusting the initial user experience to deal with the autoplay policy (e.g. showing UI to capture the gesture / advise the user, muting a media element) and then it should be up to the user what they do from there.

from autoplay.

cpearce avatar cpearce commented on August 19, 2024

My understanding from the TAG's recommendations are exactly that API should be asynchronous unless we are fairly certain that:

* they will never need a permission prompt;

Based on experimental results, Mozilla has decided to not prompt the user for permission to allow autoplay. So we don't need to worry about this here, and elsewhere, on Firefox's behalf. We will still have per-origin permissions, but they'll be managed via some other UX mechanism.

* they will never need disk access;
* they will never need network access;
* they will never need to run across processes.

My understanding is that today Safari, Chrome and Firefox are doing cross process operations with disk access to answer the question the API is asking.

Firefox does not do synchronous disk access, or have to call across processes, in order to lookup a permission for an origin. Permissions are cached in memory. When a content process loads or navigates a document, or when permissions change, that process is sent the permissions relevant to it.

Checking the document's URL against a list of allowed website (MEI for Chrome, permission for Firefox) is a disk access even if there is no input, right?

I'd assume you'd cache the MEI whitelist in memory in your main process for speed purposes, and based on what you said above it sounds like whether a document has passed the MEI threshold is already passed onto the content process when a load starts.

So you should be able to implement this API synchronously.

from autoplay.

cpearce avatar cpearce commented on August 19, 2024

I don't think we want an autoplaypolicychange event. For UAs that are blocking autoplay, this would just encourage sites to start autoplaying once the user has interacted with the site, even if they're not interacting with a video.

For example, assuming Firefox/Chrome's document activation model, user opens site, UA blocks autoplay video, user clicks an "I accept your cookie policy" button, and then the site starts to autoplay.

Also, sites can assume in most UAs that once the user has clicked or pressed a key (and played something in said event handler in the case of Safari) that they're probably allowed to play, so adding this also seems mostly redundant. Granted, it's not entirely redundant due to differences in UA blocking policies, but it does seem like something that's user hostile.

from autoplay.

 avatar commented on August 19, 2024

I'd assume you'd cache the MEI whitelist in memory in your main process for speed purposes, and based on what you said above it sounds like whether a document has passed the MEI threshold is already passed onto the content process when a load starts.

At the moment the MEI preseed and an individual users scores are in memory and we send this to all the renderer processes on navigation. However, the MEI data is growing quite a bit and we would like to potentially move this out of memory and only do the check when we actually need to.

I don't think we want an autoplaypolicychange event. For UAs that are blocking autoplay, this would just encourage sites to start autoplaying once the user has interacted with the site, even if they're not interacting with a video.

For example, assuming Firefox/Chrome's document activation model, user opens site, UA blocks autoplay video, user clicks an "I accept your cookie policy" button, and then the site starts to autoplay.

Also, sites can assume in most UAs that once the user has clicked or pressed a key (and played something in said event handler in the case of Safari) that they're probably allowed to play, so adding this also seems mostly redundant. Granted, it's not entirely redundant due to differences in UA blocking policies, but it does seem like something that's user hostile.

I agree that we should avoid having an event. It would just encourage sites to autoplay when they can rather than when they should.

from autoplay.

alastor0325 avatar alastor0325 commented on August 19, 2024

This is an old issue, which was already solved by the TAG resolution (the conclusion is to make API sync). So close this issue.

from autoplay.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.