Re: [whatwg] Fetch Objects and scripts/stylesheets
On Thu, Aug 14, 2014 at 5:28 PM, Nils Dagsson Moskopp wrote: > Ben Maurer writes: >> Another concrete example with tags: sometimes an abusive user will >> use a site like Facebook as a CDN -- they'll upload a picture and hotlink >> it from elsewhere. We could insert a time-stamped authentication token as a >> custom header. Today we sometimes do this via the query string -- giving >> the user a token that lasts for a few days. This means we bust the user's >> cache every time we rotate the token. With a custom header, the browser >> cache stays in tact. > > Why not just check the referer or origin header and act on that? That is not tied to the user. >> Images would also be a great example of where logging headers could be >> extremely helpful. For example, we could log what module within a page >> rendered an image and monitor bandwidth usage and CDN cache hit rate on a >> per module basis. In the past it's taken us a long time to debug issues >> that could easily be found with this method. > > This means more analytics and logging – privacy intrusions justified by > the sheer complexity of systems created by several thousand monkeys on > thousands of electronic typewriters. Incidentally, more fingerprinting. > > I do not see any immediate benefit to the user here. They can get this either way. E.g. the token could be put in the URL as well. Allowing custom headers makes the setup a bit nicer and actually allows developers to use the "strengths" of HTTP. -- http://annevankesteren.nl/
Re: [whatwg] Fetch Objects and scripts/stylesheets
On Wed, Aug 6, 2014 at 12:24 PM, Anne van Kesteren wrote: > I filed https://www.w3.org/Bugs/Public/show_bug.cgi?id=26533 on > investigating whether we can reuse the Request object (which is passed > to fetch(), and used in service workers to expose requests from a > window or worker). There are some complications given what can be set > through HTML and what could be set through script and how to keep > those best synchronized. > > We should be able to figure something out I think. Not sure how high > of a priority this is though. As an update, Ian proposed a more concrete plan in the bug that I think will work. I recommend people copy themselves to the bug if they want to give further feedback. -- http://annevankesteren.nl/
Re: [whatwg] Feature-detectable WakeLocks
>> I'd prefer if individual lock types were instances of objects, e.g. >> navigator.*Lock objects could be instances of a variant of the WakeLock >> interface: >> >> navigator.screenLock.request(); >> navigator.screenLock.isHeld(); >> >> navigator.cpuLock.request(); >> navigator.cpuLock.release(); >> > Personally, this doesn't strike me as good API design. It means having a > bunch of attributes that all use the same class but only differ in name. Really? I think clearly separating different classes of locks (with a common base class) is much better than conflating them behind a weakly typed string-driven API. It's like: Element.firstChild.getAttribute(…); Element.nextSibling.getAttribute(…); instead of: Element.getAttribute("firstChild", …); Element.getAttribute("nextSibling", …); >> Alternatively, if the WakeLock was instantiable (to have a standard way for >> independent page components to share locks) then these objects could be >> constructors: >> >> if (navigator.ScreenLock) { >> var lock = new navigator.ScreenLock(); >> … >> lock.release(); >> } >> >> (or `new navigator.wakeLocks.Screen()`, etc.) > We don't have any APIs like this today on the Web. It would be weird :) "Weird" is subjective and a vague criticism. Can you elaborate what's wrong with that? > It would just be better to have a constructor on the interface: `new > WakeLock("screen")` or whatever. I don't see any benefit in obscuring types of the objects. String-driven API doesn't allow simple feature detection, and a single type that conflates all lock types makes extensibility uglier. You won't be able to elegantly add methods that are valid only for some types of locks, e.g. `new WakeLock("cpu").dimScreen()` is nonsense, but would valid from perspective of WebIDL and JS prototypes. -- regards, Kornel
Re: [whatwg] Proposal: Wake Lock API
> On Monday, August 18, 2014 at 6:24 PM, Kornel Lesiński wrote: > >> I think it'd be unfortunate if this API had just one shared lock per >> browsing context and required components on the page to coordinate locking, >> but provided no means to do so. > > > The API allows scripts to check which locks are currently held (as either a > `isHeld()` or `getCurrentLocks()`, for which I just sent a PR for). I don't understand how is that helping. Let's say I have embedded a Slideshare presentation and a YouTube video on my page. I start watching slides, then start playing the video, then finish watching slides. When Slideshare finishes and wants to release the lock, it can't learn via this API whether YouTube still wants the lock. When Slideshare started isHeld was false, but setting it back to that original state would be incorrect. When Slideshare finished isHeld was true, but that doesn't tell anything either, since Slideshare itself set it to true. The only way I see for coordinating lock between independent components on the page is not via isHeld(), but by defensively re-setting the lock. In my previous example both Slideshare and YouTube would have to watch for 'lost' events (but not via the Netscape-style onlost footgun!) and keep re-requesting the lock soon after it's been released, for as long as they need it. IMHO that's really ugly. If re-requesting is supposed to be the pattern for maintaining locks properly, then the whole API could be cut down to just events: window.addEventListener('beforeScreenLock', function(e) { if (stillShowingStuff) e.preventDefault(); }, false); The browser would fire beforeScreenLock event every time the OS is about to turn the screen off. To keep the screen on for another while the page just needs to prevent the event. >> This will force authors of libraries and components to create dummy iframes >> just to have their private lock, and libraries/pages without such workaround >> will be messing up each other's locks. > > Currently, iframes are not allowed to have locks - only top-level browsing > contexts are. This is to avoid things like embedded ads from requesting wake > locks. That's a noble goal. However, it may not be effective against ads in practice, because majority of ads are embedded using
Re: [whatwg] Preventing wake lock leaks with DOM nodes
On Mon, Aug 18, 2014 at 5:35 PM, Marcos Caceres wrote: > The reason I didn't make it a boolean was because of the IPC involved and > because I wanted to support multiple types of locks without needing to add > new attributes in the future (and if we need to add the complex stuff later). What's the problem with adding more attributes in the future? That said, I do think that a "timeout" for screen locks make sense, so a boolean wouldn't work. Though not as a timeout for when to release the lock, but rather as a "minimum time I'd like to keep the screen awake" as described at http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-August/297423.html / Jonas
Re: [whatwg] Feature-detectable WakeLocks
On Mon, Aug 18, 2014 at 5:37 PM, Marcos Caceres wrote: > On Monday, August 18, 2014 at 6:41 PM, Kornel Lesiński wrote: >> WakeLock.request() expecting a string isn't very friendly to feature >> detection. > > The API tells you if a wake lock type is not supported by either rejecting > with a TypeError or by a DOMException whose name is NotSupportedError. We've made this mistake before. See http://robert.ocallahan.org/2012/05/canvas-getcontext-mistake.html / Jonas
Re: [whatwg] Proposal: Wake Lock API
On Mon, Aug 18, 2014 at 4:37 PM, Marcos Caceres wrote: >> while(navigator.wakeLock.isHeld("screen")) >> navigator.wakeLock.release("screen"); // just release the damn thing in my >> leaky code! > > That would just halt the browser as the script would never complete: > currently releasing happens async once the system acknowledges that the > release has been granted. I'm not sure if there is a use case for that > behavior - it's just what is currently/sorta roughly proposed in the spec. I don't think the sync part was the important aspect here. You could easily rewrite that as an async loop. The point is that it's easy for developers to end up trying to work around bugs in their own code by simply doing extra releases. Or end up with bugs where they accidentally release too many times and so stomp on other components. >> Therefore, if WakeLock needs to be purely JS API, I strongly prefer having >> WakeLock available only as an object instance, but without exposing GC >> behavior--if it's lost, it's like a missing release call. >> >> If devtools ever get monitoring of unhanded errors in Promise objects, they >> could also warn against lost WakeLock objects--it's the same type of problem >> dependent on GC. >> >> I'm assuming that release would work only once on each lock object: >> >> var lock = new WakeLock("screen"); >> lock.release(); >> lock.release(); // ignored, so it doesn't unlock any other component's lock >> >> This makes coordination easier: each page component can easily create their >> own lock independently (without needing to create an iframe to get their own >> lock), and can't release any other component's lock. > > Personally, I don't know if I agree that it makes coordination easier. Seems > that having a centralized place to check what is currently being held makes > life a lot easier, because it allows scripts to check if they actually need > to request a lock or not. Why does the ability to check if a lock is held make coordination easier? Checking if they need to request a lock or if someone else is already doing it seems like a very bad code pattern which actually makes coordination harder. It makes it very easy to get confused and try to rely on party X to hold a lock, but then it turns out that in reality it was Y holding the lock, but Y releases the lock much sooner and now end up holding a lock for a shorter time than intended. Am I missing something? > If you have some objects requesting and others releasing, then it makes a > huge mess because you need to track down which object screwed up the lock. This is not what the proposal is. The proposal is that if a WakeLock instance x is used to grab a lock, then the lock will be held until x.release() is called. Any calls on other WakeLock instances will not cause the lock to be released. Only one all WakeLock instances that have had request() called on them also gets a call to release(), does the lock get released. Losing track of the instance that you called request() on, then that is equivalent to losing track of how many time you have called wakeLock.request(x). There is no way to get correctly out of that situation. > And if GC also then works to release the locks, then there is no certainty as > to what is actually releasing the lock or when. Can we please stop talking about GC. I don't think anyone has made a serious proposal where GC releases a lock, or where GC is otherwise exposed. / Jonas
Re: [whatwg] Feature-detectable WakeLocks
On Monday, August 18, 2014 at 6:41 PM, Kornel Lesiński wrote: > WakeLock.request() expecting a string isn't very friendly to feature > detection. The API tells you if a wake lock type is not supported by either rejecting with a TypeError or by a DOMException whose name is NotSupportedError. > > I'd prefer if individual lock types were instances of objects, e.g. > navigator.*Lock objects could be instances of a variant of the WakeLock > interface: > > navigator.screenLock.request(); > navigator.screenLock.isHeld(); > > navigator.cpuLock.request(); > navigator.cpuLock.release(); > Personally, this doesn't strike me as good API design. It means having a bunch of attributes that all use the same class but only differ in name. > > > Alternatively, if the WakeLock was instantiable (to have a standard way for > independent page components to share locks) then these objects could be > constructors: > > if (navigator.ScreenLock) { > var lock = new navigator.ScreenLock(); > … > lock.release(); > } > > (or `new navigator.wakeLocks.Screen()`, etc.) We don't have any APIs like this today on the Web. It would be weird :) It would just be better to have a constructor on the interface: `new WakeLock("screen")` or whatever. But then we are just back discussing the other email about GC, etc. > Having specific instances for different types of locks could also enable > elegant extensibility of the API, e.g. > > var screenLock = new navigator.ScreenLock(); > screenLock.dimScreen(); // completely made-up API > > var cpuLock = new navigator.CpuLock(); > cpuLock.setThreadPriority("low"); // completely made-up API > IMO, this is not really different from: navigator.wakeLock.request("cpu", { setThreadPriority: "low" }); If we need to start returning an actual WakeLock objects in the future, we can add that.
Re: [whatwg] Preventing wake lock leaks with DOM nodes
(sorry, accidental send before!) On Monday, August 18, 2014 at 8:10 PM, Domenic Denicola wrote: > In general I feel this thread has taken a turn for the complex. Why don't we > just do what other platforms do, and provide a simple global request/release > mechanism (or toggleable Boolean property!), which developers can build on > top of? A lot of the ideas here seem to be trying to create the perfect, > developer-friendly, foolproof API. Some of them seem quite clever too, tying > to page visibility and the like. But all of them could be built, as > libraries, on top of a global request/release. That way users could get > reference counting if they want that, visibility-based locking if they want > that, promise-based locking if they want that, timeouts if they want those, > or even just not do any of those if their use case is simple enough that it > doesn't warrant anything more complicated than what they are already doing on > existing platforms. The reason I didn't make it a boolean was because of the IPC involved and because I wanted to support multiple types of locks without needing to add new attributes in the future (and if we need to add the complex stuff later). The request()/release() mechanism is well suited for that, IMO. And it's also fairly simple, even if it vends a promise. Admittedly, I could just make it a bunch of boolean attributes. The spec is kinda already designed to work that way (what lock is applied is just a flag, which is checked synchronously)... it's how `isHeld(lockType)` works. About tying it to visibility, and time, etc. Those are nice to have, but can certainly do without for now. We already dropped the timeout stuff from the original spec - but certainly a nice to have in the future. Having said that, if we know that this API is going to be used in conjunction with scroll events, then we know we are going to have potential battery eating problems (beyond just keeping the screen on). > > We don't need to solve Hard Problems in Programming (TM) before we expose a > wake lock API. Leave that as a subsequent step, which users can do, while we > move on to exposing more missing platform capabilities > Yeah, certainly want to keep it as simple as possible. Just want to cover keeping the screen on for now.
Re: [whatwg] Preventing wake lock leaks with DOM nodes
On Monday, August 18, 2014 at 8:10 PM, Domenic Denicola wrote: > In general I feel this thread has taken a turn for the complex. Why don't we > just do what other platforms do, and provide a simple global request/release > mechanism (or toggleable Boolean property!), which developers can build on > top of? A lot of the ideas here seem to be trying to create the perfect, > developer-friendly, foolproof API. Some of them seem quite clever too, tying > to page visibility and the like. But all of them could be built, as > libraries, on top of a global request/release. That way users could get > reference counting if they want that, visibility-based locking if they want > that, promise-based locking if they want that, timeouts if they want those, > or even just not do any of those if their use case is simple enough that it > doesn't warrant anything more complicated than what they are already doing on > existing platforms. > > We don't need to solve Hard Problems in Programming (TM) before we expose a > wake lock API. Leave that as a subsequent step, which users can do, while we > move on to exposing more missing platform capabilities
Re: [whatwg] Preventing wake lock leaks with DOM nodes
On Mon, Aug 18, 2014 at 5:10 PM, Domenic Denicola wrote: > In general I feel this thread has taken a turn for the complex. Why don't we > just do what other platforms do, and provide a simple global request/release > mechanism (or toggleable Boolean property!), which developers can build on > top of? A lot of the ideas here seem to be trying to create the perfect, > developer-friendly, foolproof API. Some of them seem quite clever too, tying > to page visibility and the like. But all of them could be built, as > libraries, on top of a global request/release. That way users could get > reference counting if they want that, visibility-based locking if they want > that, promise-based locking if they want that, timeouts if they want those, > or even just not do any of those if their use case is simple enough that it > doesn't warrant anything more complicated than what they are already doing on > existing platforms. > > We don't need to solve Hard Problems in Programming (TM) before we expose a > wake lock API. Leave that as a subsequent step, which users can do, while we > move on to exposing more missing platform capabilities Nope, doesn't work. You can't build anything more complex on top of a simple request/release (or a boolean, which is equivalent), because any other library can come along and screw with the lock. So, if we want this to be extensible, we still need to design it in a localized way so that you can have multiple independent locks. If we did that, we *could* then layer a visibility/promise-based thing on top as an auto-release mechanism for a specific lock. But you've still got to solve at least one problem correctly. ~TJ
Re: [whatwg] Preventing wake lock leaks with DOM nodes
In general I feel this thread has taken a turn for the complex. Why don't we just do what other platforms do, and provide a simple global request/release mechanism (or toggleable Boolean property!), which developers can build on top of? A lot of the ideas here seem to be trying to create the perfect, developer-friendly, foolproof API. Some of them seem quite clever too, tying to page visibility and the like. But all of them could be built, as libraries, on top of a global request/release. That way users could get reference counting if they want that, visibility-based locking if they want that, promise-based locking if they want that, timeouts if they want those, or even just not do any of those if their use case is simple enough that it doesn't warrant anything more complicated than what they are already doing on existing platforms. We don't need to solve Hard Problems in Programming (TM) before we expose a wake lock API. Leave that as a subsequent step, which users can do, while we move on to exposing more missing platform capabilities > On Aug 18, 2014, at 19:52, "Marcos Caceres" wrote: > > > >> On Monday, August 18, 2014 at 7:21 PM, Kornel Lesiński wrote: >> >> My biggest concern with the WakeLock API is that it's easy to forget (or >> fail) to release the lock. >> >> It's not a problem with the API per se, but a programming problem in >> general: resource management in non-trivial programs is hard. WakeLocks are >> especially problematic in this regard, as a "leaked" lock won't cause any >> immediate problems for the developer, so this type of bug can easily go >> unnoticed. > > Sure. At least on a mobile device, it's easy enough for the user to turn off > the screen (or just switch apps or browser tabs)... on laptops, it could be a > problem. However, MacOS (at least) is pretty good at telling users if an app > is eating too much battery. So this could be also handled at the system > level. >> So I think lifetime of WakeLocks needs to be attached to something visible >> to make failure to we release the lock immediately obvious. >> >> >> In case of screen lock it's especially easy: the whole purpose of this lock >> is to keep something visible on screen, so we can require that something to >> be explicitly connected to the lock. > > I think that would be nice, actually. It's at least a kinda workaround to > having to check if something is in the drawable area manually. > > However, it still doesn't really deal with the case where the dev forgets to > release the lock. What is nicer is combining this with a timeout: > > navigator.wakeLock.request("screen", {element: myCanvas, timeout: > aFewMinutes}); > > That would be the most ideal solution for me personally. Just set it, and > forget it. > >> It's nearly impossible to forget to remove a visible DOM element from the >> document — the mistake is likely to be quite obviously visible. If screen >> lock lifetime was dependent on visibility of a DOM element, then it would >> also be very hard to leak the lock without noticing it! >> >> (that's a variant of "wake-lock:display" CSS proposal, but less explicitly >> dependent on CSS). > > Yes, absolutely. So long as CSS lacks some way to detect if something is > offscreen, it makes sense. The current ways of checking if an element is > within the viewport are quite expensive (bunch of jQuery plugins do this - > and I think they depend on the onscroll event). >> With CPU lock it's less clear cut. I think tying it to a notification may be >> a good idea. > > Need to think about it. >> Alternatively, perhaps the lock itself could be an instance of the >> element that author is supposed to insert to the document? ;) > > heh:) Yeah, need to think about that. > >
Re: [whatwg] Preventing wake lock leaks with DOM nodes
On Monday, August 18, 2014 at 7:21 PM, Kornel Lesiński wrote: > My biggest concern with the WakeLock API is that it's easy to forget (or > fail) to release the lock. > > It's not a problem with the API per se, but a programming problem in general: > resource management in non-trivial programs is hard. WakeLocks are especially > problematic in this regard, as a "leaked" lock won't cause any immediate > problems for the developer, so this type of bug can easily go unnoticed. Sure. At least on a mobile device, it's easy enough for the user to turn off the screen (or just switch apps or browser tabs)... on laptops, it could be a problem. However, MacOS (at least) is pretty good at telling users if an app is eating too much battery. So this could be also handled at the system level. > So I think lifetime of WakeLocks needs to be attached to something visible to > make failure to release the lock immediately obvious. > > > In case of screen lock it's especially easy: the whole purpose of this lock > is to keep something visible on screen, so we can require that something to > be explicitly connected to the lock. I think that would be nice, actually. It's at least a kinda workaround to having to check if something is in the drawable area manually. However, it still doesn't really deal with the case where the dev forgets to release the lock. What is nicer is combining this with a timeout: navigator.wakeLock.request("screen", {element: myCanvas, timeout: aFewMinutes}); That would be the most ideal solution for me personally. Just set it, and forget it. > It's nearly impossible to forget to remove a visible DOM element from the > document — the mistake is likely to be quite obviously visible. If screen > lock lifetime was dependent on visibility of a DOM element, then it would > also be very hard to leak the lock without noticing it! > > (that's a variant of "wake-lock:display" CSS proposal, but less explicitly > dependent on CSS). Yes, absolutely. So long as CSS lacks some way to detect if something is offscreen, it makes sense. The current ways of checking if an element is within the viewport are quite expensive (bunch of jQuery plugins do this - and I think they depend on the onscroll event). > With CPU lock it's less clear cut. I think tying it to a notification may be > a good idea. Need to think about it. > Alternatively, perhaps the lock itself could be an instance of the > element that author is supposed to insert to the document? ;) heh:) Yeah, need to think about that.
Re: [whatwg] Proposal: Wake Lock API
On Monday, August 18, 2014 at 6:24 PM, Kornel Lesiński wrote: > I think it'd be unfortunate if this API had just one shared lock per browsing > context and required components on the page to coordinate locking, but > provided no means to do so. The API allows scripts to check which locks are currently held (as either a `isHeld()` or `getCurrentLocks()`, for which I just sent a PR for). > This will force authors of libraries and components to create dummy iframes > just to have their private lock, and libraries/pages without such workaround > will be messing up each other's locks. Currently, iframes are not allowed to have locks - only top-level browsing contexts are. This is to avoid things like embedded ads from requesting wake locks. > Having just a single shared DOM0-style event handler > navigator.wakeLock.onlost looks especially jarring. I would expect this to be > a proper DOM event that can be used with normal addEventListener (please > avoid repeating the mistake of matchMedia). Oops! I forgot to put that `WakeLock` inherits from `EventTarget`. It's always been the intention that you will have .addEventListener! I've sent a PR to fix this. > To make some coordination possible, the simplest method could be to keep > track of number of lock requests and releases, like retain/release in > Objective-C: > > navigator.wakeLock.request("screen"); // locks > navigator.wakeLock.request("screen"); // increases lock count > navigator.wakeLock.release("screen"); // not released yet, but decreases lock > count > navigator.wakeLock.release("screen"); // now released for real In my dummy implementation, I've just been using (the Swift equivalent of): [UIApplication sharedApplication].idleTimerDisabled = YES; On MacOS, I thought the "right thing to do" (tm) according to Apple was [1] (see listing 2)? I'm pretty sure that's what we do already in Gecko for videos as we've been investigating repurposing the video code for wake locks. So, I've not seen the request/release behavior you describe above (at least not in the context of wake locks on MacOS/iOS). I guess it's used as an idiom maybe in other places? > However, as you probably know from Objective-C, Full disclosure, I barely know objective-c ;) > perfect balancing of retain/release takes care and discipline. Personally, I > wouldn't trust all 3rd party libraries/widgets/ads to be careful with this. > In fact, I expect some "clever" libraries to ruin this with: > > while(navigator.wakeLock.isHeld("screen")) > navigator.wakeLock.release("screen"); // just release the damn thing in my > leaky code! That would just halt the browser as the script would never complete: currently releasing happens async once the system acknowledges that the release has been granted. I'm not sure if there is a use case for that behavior - it's just what is currently/sorta roughly proposed in the spec. > Therefore, if WakeLock needs to be purely JS API, I strongly prefer having > WakeLock available only as an object instance, but without exposing GC > behavior—if it's lost, it's like a missing release call. > > If devtools ever get monitoring of unhanded errors in Promise objects, they > could also warn against lost WakeLock objects—it's the same type of problem > dependent on GC. > > I'm assuming that release would work only once on each lock object: > > var lock = new WakeLock("screen"); > lock.release(); > lock.release(); // ignored, so it doesn't unlock any other component's lock > > This makes coordination easier: each page component can easily create their > own lock independently (without needing to create an iframe to get their own > lock), and can't release any other component's lock. Personally, I don't know if I agree that it makes coordination easier. Seems that having a centralized place to check what is currently being held makes life a lot easier, because it allows scripts to check if they actually need to request a lock or not. If you have some objects requesting and others releasing, then it makes a huge mess because you need to track down which object screwed up the lock. And if GC also then works to release the locks, then there is no certainty as to what is actually releasing the lock or when. [1] https://developer.apple.com/library/mac/qa/qa1340/_index.html
Re: [whatwg] Preventing wake lock leaks with DOM nodes
On Mon, Aug 18, 2014 at 4:21 PM, Kornel Lesiński wrote: > My biggest concern with the WakeLock API is that it's easy to forget (or > fail) to release the lock. > > It's not a problem with the API per se, but a programming problem in general: > resource management in non-trivial programs is hard. WakeLocks are especially > problematic in this regard, as a "leaked" lock won't cause any immediate > problems for the developer, so this type of bug can easily go unnoticed. > > So I think lifetime of WakeLocks needs to be attached to something visible to > make failure to release the lock immediately obvious. > > > In case of screen lock it's especially easy: the whole purpose of this lock > is to keep something visible on screen, so we can require that something to > be explicitly connected to the lock. > > For example if I were creating a widget that displays a presentation on the > page, I could attach the screen lock to the or element that > holds the presentation: > > new navigator.ScreenLock(myCanvas); > > and if the canvas was removed from the document or hidden in any way, then > the browser could turn the screen off as usual, and I wouldn't have to do > anything! > > It's nearly impossible to forget to remove a visible DOM element from the > document — the mistake is likely to be quite obviously visible. If screen > lock lifetime was dependent on visibility of a DOM element, then it would > also be very hard to leak the lock without noticing it! > > (that's a variant of "wake-lock:display" CSS proposal, but less explicitly > dependent on CSS). Good, but you lose the ability to key the wake-lock to Selectors-exposed UA state (like "video:playing"), or directly to your app's own state (via some class that gets set/removed by your app at some point in its lifecycle). But if the CSS part is distasteful, I agree that this works reasonably well - there is *absolutely no reason* to screenlock based on an element that's not visible on screen. > With CPU lock it's less clear cut. I think tying it to a notification may be > a good idea. Alternatively, perhaps the lock itself could be an instance of > the element that author is supposed to insert to the document? ;) Just pass a promise to the CpuLock constructor, and have it auto-release when the promise is settled? You'll generally be CPU-locking to wait for some operation to finish, and a lot of those types of operations vend promises these days (or will in the future). ~TJ
[whatwg] Preventing wake lock leaks with DOM nodes
My biggest concern with the WakeLock API is that it's easy to forget (or fail) to release the lock. It's not a problem with the API per se, but a programming problem in general: resource management in non-trivial programs is hard. WakeLocks are especially problematic in this regard, as a "leaked" lock won't cause any immediate problems for the developer, so this type of bug can easily go unnoticed. So I think lifetime of WakeLocks needs to be attached to something visible to make failure to release the lock immediately obvious. In case of screen lock it's especially easy: the whole purpose of this lock is to keep something visible on screen, so we can require that something to be explicitly connected to the lock. For example if I were creating a widget that displays a presentation on the page, I could attach the screen lock to the or element that holds the presentation: new navigator.ScreenLock(myCanvas); and if the canvas was removed from the document or hidden in any way, then the browser could turn the screen off as usual, and I wouldn't have to do anything! It's nearly impossible to forget to remove a visible DOM element from the document — the mistake is likely to be quite obviously visible. If screen lock lifetime was dependent on visibility of a DOM element, then it would also be very hard to leak the lock without noticing it! (that's a variant of "wake-lock:display" CSS proposal, but less explicitly dependent on CSS). With CPU lock it's less clear cut. I think tying it to a notification may be a good idea. Alternatively, perhaps the lock itself could be an instance of the element that author is supposed to insert to the document? ;) -- regards, Kornel
[whatwg] Feature-detectable WakeLocks
WakeLock.request() expecting a string isn't very friendly to feature detection. I'd prefer if individual lock types were instances of objects, e.g. navigator.*Lock objects could be instances of a variant of the WakeLock interface: navigator.screenLock.request(); navigator.screenLock.isHeld(); navigator.cpuLock.request(); navigator.cpuLock.release(); Alternatively, if the WakeLock was instantiable (to have a standard way for independent page components to share locks) then these objects could be constructors: if (navigator.ScreenLock) { var lock = new navigator.ScreenLock(); … lock.release(); } (or `new navigator.wakeLocks.Screen()`, etc.) Having specific instances for different types of locks could also enable elegant extensibility of the API, e.g. var screenLock = new navigator.ScreenLock(); screenLock.dimScreen(); // completely made-up API var cpuLock = new navigator.CpuLock(); cpuLock.setThreadPriority("low"); // completely made-up API -- regards, Kornel
Re: [whatwg] Proposal: Wake Lock API
I think it'd be unfortunate if this API had just one shared lock per browsing context and required components on the page to coordinate locking, but provided no means to do so. This will force authors of libraries and components to create dummy iframes just to have their private lock, and libraries/pages without such workaround will be messing up each other's locks. Having just a single shared DOM0-style event handler navigator.wakeLock.onlost looks especially jarring. I would expect this to be a proper DOM event that can be used with normal addEventListener (please avoid repeating the mistake of matchMedia). To make some coordination possible, the simplest method could be to keep track of number of lock requests and releases, like retain/release in Objective-C: navigator.wakeLock.request("screen"); // locks navigator.wakeLock.request("screen"); // increases lock count navigator.wakeLock.release("screen"); // not released yet, but decreases lock count navigator.wakeLock.release("screen"); // now released for real However, as you probably know from Objective-C, perfect balancing of retain/release takes care and discipline. Personally, I wouldn't trust all 3rd party libraries/widgets/ads to be careful with this. In fact, I expect some "clever" libraries to ruin this with: while(navigator.wakeLock.isHeld("screen")) navigator.wakeLock.release("screen"); // just release the damn thing in my leaky code! Therefore, if WakeLock needs to be purely JS API, I strongly prefer having WakeLock available only as an object instance, but without exposing GC behavior—if it's lost, it's like a missing release call. If devtools ever get monitoring of unhanded errors in Promise objects, they could also warn against lost WakeLock objects—it's the same type of problem dependent on GC. I'm assuming that release would work only once on each lock object: var lock = new WakeLock("screen"); lock.release(); lock.release(); // ignored, so it doesn't unlock any other component's lock This makes coordination easier: each page component can easily create their own lock independently (without needing to create an iframe to get their own lock), and can't release any other component's lock. -- regards, Kornel
Re: [whatwg] Proposal: Wake Lock API
On Mon, Aug 18, 2014 at 2:04 AM, Mounir Lamouri wrote: > >> > It's also not clear >> > how this solution is superior than the current solution [1] with regards >> > to multiple releases or requests. In [1], if you call .request() or >> > .release() multiple time, the promise reacts appropriately. >> >> The problem arises when you have several semi-independent pieces of >> code within a single page. Given that request() and release() is >> likely going to happen in response to very different UI events or IO >> events, it makes it fairly easy to accidentally have unbalanced calls. >> >> Consider for example a lock which is released either when a video >> reaches its end, when the user presses the pause button, or when the >> user close the in which the video is rendered. It seems quite >> easy to end up with a race where if the user close the right >> when the video ends, that release() would get called twice. Or if the >> user pause the video first and then close the that release() >> would get called twice. >> >> If there's only one subsystem of the page that uses a display lock, >> then this is not a big deal. The extra call to release() would cause >> an rejection, but hopefully that won't break the page. > > It is possible that the API might behave differently and the first > release() will release the lock even if lock() was called multiple > times. I guess the scope of the lock could be the browsing context so a > website will not end up conflicting with iframes. However, if a websites > embeds libraries that use this API, it will need to coordinate. I'd rather have request() and release() work as they are defined now. Otherwise coordinating becomes even harder as the specification does not provide a coordination mechanism. >> However if there are multiple subsystems that all use a display lock, >> it would mean that those subsystems might stomp on each other's >> attempts at holding a display lock. The effect would be that the >> display lock is released too early. >> >> I don't care strongly about this though. It's pretty easy for pages to >> write a wrapper around the currently proposed API to implement the API >> that I'm proposing. > > I understand the problem and I agree that an object-based approach would > be nicer in theory because the scope of the lock would be well defined. > However, it's a very uncommon pattern as far as Web APIs are concerned > and I would worry that developers would end up doing things wrong and > depend on the GC behaviour without even being aware of it. Note that in the API that I'm proposing, there is no way to accidentally rely on GC behavior. If a WakeLock object is GCed before it has been release()ed, then the lock is held indefinitely (until the user leaves the page of course). I.e. an unbalanced request() and release() in both the currently proposed API, and in the API that I propose behave the same, the lock is held indefinitely. Any objects getting GCed does not change this. Again, I don't feel terribly strongly about this as it's easy to shim in either direction. / Jonas
Re: [whatwg] Proposal: Wake Lock API
On Sat, Aug 16, 2014 at 9:19 AM, Nils Dagsson Moskopp wrote: > Jonas Sicking writes: >> On Fri, Aug 15, 2014 at 6:14 AM, Mounir Lamouri wrote: >>> On Thu, 14 Aug 2014, at 11:00, Jonas Sicking wrote: I am however more worried about that only having a request() and a release() function means that pages that contain multiple independent subsystems will have to make sure that they don't stomp on each other's locks. Simply counting request() calls vs. release() calls helps, but doesn't fully solve the problem. It's very easy to accidentally call release too many times, in response to some UI action for example. An alternative design would be something like x = new WakeLock("display"); x.request(); x.release(); Extra calls of either request() or release() are ignored, but pages can create any number of WakeLocks of the same type. >>> >>> It seems that we already discussed using an object and this solution was >>> dismissed because of this model being error-prone. >> >> Where was this discussed? Why was it considered more error prone? Was >> it related to the patterns discussed at >> >> http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-August/297431.html >> >>> It's also not clear >>> how this solution is superior than the current solution [1] with regards >>> to multiple releases or requests. In [1], if you call .request() or >>> .release() multiple time, the promise reacts appropriately. >> >> The problem arises when you have several semi-independent pieces of >> code within a single page. Given that request() and release() is >> likely going to happen in response to very different UI events or IO >> events, it makes it fairly easy to accidentally have unbalanced calls. >> >> Consider for example a lock which is released either when a video >> reaches its end, when the user presses the pause button, or when the >> user close the in which the video is rendered. It seems quite >> easy to end up with a race where if the user close the right >> when the video ends, that release() would get called twice. Or if the >> user pause the video first and then close the that release() >> would get called twice. > > Seems to me a declarative solution (like CSS) might be appropriate. > > @media screen { > video:playing { > wake-lock: display 15s; > } > } > > article.recipe:target { > wake-lock: display; > } That's not a terrible idea. The CSSWG is generally hesitant to put behavior-altering things in CSS, but some bleed-through is fine, and this can be argued as an aspect of appearance. This solves the GC and locking issues (the latter by delegating state management to CSS, which everyone already knows to use). ~TJ
Re: [whatwg] Proposal: Wake Lock API
On Sat, 16 Aug 2014, at 08:40, Jonas Sicking wrote: > On Fri, Aug 15, 2014 at 6:14 AM, Mounir Lamouri > wrote: > > On Thu, 14 Aug 2014, at 11:00, Jonas Sicking wrote: > >> I am however more worried about that only having a request() and a > >> release() function means that pages that contain multiple independent > >> subsystems will have to make sure that they don't stomp on each > >> other's locks. Simply counting request() calls vs. release() calls > >> helps, but doesn't fully solve the problem. It's very easy to > >> accidentally call release too many times, in response to some UI > >> action for example. > >> > >> An alternative design would be something like > >> > >> x = new WakeLock("display"); > >> x.request(); > >> x.release(); > >> > >> Extra calls of either request() or release() are ignored, but pages > >> can create any number of WakeLocks of the same type. > > > > It seems that we already discussed using an object and this solution was > > dismissed because of this model being error-prone. > > Where was this discussed? Why was it considered more error prone? Was > it related to the patterns discussed at > http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-August/297431.html There might have been some discussions in the DAP WG (but the archives website isn't helping). There was definitely at thread in blink-dev [1] and you might want to have a look at the GitHub repo [2]. By the way, it seems that this API might be worked in the DAP WG [3]. > > It's also not clear > > how this solution is superior than the current solution [1] with regards > > to multiple releases or requests. In [1], if you call .request() or > > .release() multiple time, the promise reacts appropriately. > > The problem arises when you have several semi-independent pieces of > code within a single page. Given that request() and release() is > likely going to happen in response to very different UI events or IO > events, it makes it fairly easy to accidentally have unbalanced calls. > > Consider for example a lock which is released either when a video > reaches its end, when the user presses the pause button, or when the > user close the in which the video is rendered. It seems quite > easy to end up with a race where if the user close the right > when the video ends, that release() would get called twice. Or if the > user pause the video first and then close the that release() > would get called twice. > > If there's only one subsystem of the page that uses a display lock, > then this is not a big deal. The extra call to release() would cause > an rejection, but hopefully that won't break the page. It is possible that the API might behave differently and the first release() will release the lock even if lock() was called multiple times. I guess the scope of the lock could be the browsing context so a website will not end up conflicting with iframes. However, if a websites embeds libraries that use this API, it will need to coordinate. > However if there are multiple subsystems that all use a display lock, > it would mean that those subsystems might stomp on each other's > attempts at holding a display lock. The effect would be that the > display lock is released too early. > > I don't care strongly about this though. It's pretty easy for pages to > write a wrapper around the currently proposed API to implement the API > that I'm proposing. I understand the problem and I agree that an object-based approach would be nicer in theory because the scope of the lock would be well defined. However, it's a very uncommon pattern as far as Web APIs are concerned and I would worry that developers would end up doing things wrong and depend on the GC behaviour without even being aware of it. [1] https://groups.google.com/a/chromium.org/d/msg/blink-dev/SzVuAi2KRhA/OaNDiHOKl8gJ [2] https://github.com/w3c/wake-lock [3] http://lists.w3.org/Archives/Public/public-device-apis/2014Aug/0035.html -- Mounir