ISSUE-167: Should Promises be used in Battery API
Should Promises be used in Battery API
- State:
- PENDING REVIEW
- Product:
- Battery Status API
- Raised by:
- Frederick Hirsch
- Opened on:
- 2014-08-04
- Description:
- Raised on behalf of Rick Waldron <waldron.rick@gmail.com>
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0008.html
[[
Is there a design history document or thread that explains the reasoning
that lead to an API that returns a promise here? The battery exists before
the browser ever loads a site and its JavaScript files, so why does
`getBattery` need to be a promise? The "latest published" Battery Status
API spec makes more sense: navigator.battery is always a single instance of
BatteryManager that exists as specified here:
http://www.w3.org/TR/battery-status/#navigatorbattery-interface . Why does
it need to be "requested" via a "getBattery" API that itself doesn't return
a BatteryManager object, but promises to produce one (and always the same
one)?
If it's always the same BatteryManager instance, it's not clear how this
API usage:
navigator.getBattery().then(function(battery) {
battery.onlevelchange = function() {
console.log("level changed!");
};
});
... is at all superior to this:
navigator.battery.onlevelchange = function() {
console.log("level changed!");
});
Even if the argument is that not all code needs or wants to allocate the
BatteryManager, then the solution is simply to make `navigator.battery` an
accessor to the BatteryManager instance.
]]
- Related Actions Items:
- No related actions
- Related emails:
- Re: DAP-ISSUE-169: Battery API needs to be more event driven and async, less device centric. [Battery Status API] (from anssi.kostiainen@intel.com on 2014-08-11)
- Re: DAP-ISSUE-167: Should Promises be used in Battery API [Battery Status API] (from anssi.kostiainen@intel.com on 2014-08-08)
- Re: DAP-ISSUE-167: Should Promises be used in Battery API [Battery Status API] (from anssi.kostiainen@intel.com on 2014-08-08)
- draft minutes from today's teleconference, 7 Aug 2014 (from w3c@fjhirsch.com on 2014-08-07)
- [admin] Agenda - DAP Distributed Meeting 7 August 2014 (from w3c@fjhirsch.com on 2014-08-04)
- [battery] Battery Issue summary and status (from w3c@fjhirsch.com on 2014-08-04)
- DAP-ISSUE-167: Should Promises be used in Battery API [Battery Status API] (from sysbot+tracker@w3.org on 2014-08-04)
Related notes:
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0010.html
[[
See
http://lists.w3.org/Archives/Public/public-device-apis/2014Apr/0037.html
There was a CfC about that too.
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0012.html
[[
From: Rick Waldron <waldron.rick@gmail.com>
> Is there a design history document or thread that explains the reasoning that lead to an API that returns a promise here? The battery exists before the browser ever loads a site and its JavaScript files, so why does `getBattery` need to be a promise?
This is a great point, and a non-normative note would be helpful. My assumption was that it was so you could lazy-load battery-related code, or perhaps that battery information is stored out of process and thus some asynchronous prep-work must be done to make it available. I have no idea though and some help from implementers would be great.
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0014.html
[[
As implemented in the latest stable Firefox, which is version 30,
navigator.battery has the appearance of a pre initialized
BatteryManager—though it may just be a synchronous accessor the produces
the BatteryManager on [[Get]].
The CFC that Mounir linked to says only this "This will allow for less
constrained and more efficient current and future implementations." and
doesn't provide any supporting cases for this claim. Furthermore, Marcos
Caceres mentions multiple batteries in a later message[0], a use case that
can't be addressed by this change anyway (which battery does
getBattery().then(...) resolve with???). Even multiple batteries exist
before the browser loads anything, so it's still unclear why the API needs
to be promise-based.
Rick
[0] http://lists.w3.org/Archives/Public/public-device-apis/2014Apr/0039.html
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0015.html
[[
the current draft is treating multiple batteries as a single battery - hence you do not have ability to query different batteries, just the single virtual battery (e.g. all batteries treated as a single battery composed of the multiple batteries).
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0016.html
[[
That make sense and actually sort of mimics lipoly multi-cell battery
design.
Rick
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0036.html
[[
> Yes, I guess I was not clear. My original post was mainly about
> questioning whether this is a good recommendation, instead of forcing
> authors to handle the failure path. Thus "I realize that the default values
> idea might have been a result of a previous discussion that I missed, and
> would be happy to be pointed toward it." The name is not the important
> part; indeed for back-compat and reduced churn I might imagine we want to
> keep getBattery().
>
If back-compat is a concern, then be concerned about changing from
navigator.battery (a synchronous accessor, that behaves as synchronous
hardware APIs should) to the unnecessarily async navigator.getBattery that
doesn't get a BatteryManager, but instead a promise, that will in turn
resolve to a BatteryManager.
I have yet to see any compelling (or even informative) discussion that
supports this change. The previously linked "CFC" was vague at best.
Rick
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0037.html
[[
> This is a great point, and a non-normative note would be helpful. My
> assumption was that it was so you could lazy-load battery-related code,
> or perhaps that battery information is stored out of process and thus
> some asynchronous prep-work must be done to make it available. I have no
> idea though and some help from implementers would be great.
As far as I am concerned, getBattery doesn't need to be a promise. This
is why the original specification was a property. The reason was that it
would be possible for the UA to do the work you mentioned. However,
implementers (in that case Google) expressed concerned that it was
adding a requirement on the UA that wasn't future-proof. In other words,
some UA might have a design that would make this very hard to do if
doable. Google proposed the change, Mozilla agreed.
-- Mounir
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0038.html
[[
One of the reasons we want to avoid synchronous access to battery is
because it's harder to implement efficiently. For example in chrome you
would either need a synchronous IPC or fetch the data on startup and keep
track of it at all times, neither of which seemed acceptable hence the
asynchronous proposal.
Tim
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0039.html
[[
> One of the reasons we want to avoid synchronous access to battery is
> because it's harder to implement efficiently. For example in chrome you
> would either need a synchronous IPC or fetch the data on startup and keep
> track of it at all times, neither of which seemed acceptable hence the
> asynchronous proposal.
>
FirefoxOS/gaia/etc. has been shipping the navigator.battery API since 2012.
I've been searching for reports that would support this claim based on
their implementation, but cannot find anything. (Tizen ships it as well,
but I have no experience there). On non-web platforms, eg. Android, iOS,
the Battery[Manager|Status] objects are synchronous and can be used with
observer and broadcaster patterns. With all respect, I find it hard to
believe and accept that the creation of the BatteryManager object (only one
ever) is of substantial burden. Presumably, if a device has a battery it
also _always_ knows the state of that battery—this has been my experience,
but perhaps chrome is expected to run on devices where this doesn't hold
true?
Simply put, the change from:
navigator.battery
to:
navigator.getBattery().then(function(battery) {
...
});
...changes the API from good to bad and ignores the two years of
implementation experience that has accumulated for the latter. Perhaps
before this change is accepted, or even seriously considered, the existing
Candidate Recommendation specification can be implemented and studied.
Rick
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0040.html
[[
Rick, Chromium has a multi-process architecture, whereas Firefox in general keeps most things in a single process. Thus Firefox has the ability to implement many more things synchronously than Chromium does. Implementation experience based on a single vendor is not terribly valuable in guiding API surface, especially in questions of sync vs. async, and especially when that vendor is Firefox (the only single-process modern browser, from what I understand).
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0041.html
[[
> Simply put, the change from:
>
> navigator.battery
>
> to:
>
> navigator.getBattery().then(function(battery) {
> ...
> });
>
>
> ...changes the API from good to bad and ignores the two years of
> implementation experience that has accumulated for the latter. Perhaps
> before this change is accepted, or even seriously considered, the existing
> Candidate Recommendation specification can be implemented and studied.
I have to agree with Rick. There doesn't appear to be a valid reason to make this change.
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0042.html
[[
Can't we just add `readonly attribute Promise isReady` (yes, we can bikeshed) to the current interface? That should can serve as a signal without needing to change the existing API (and can continue to work as it does today in Gecko without needing the API to be refactored).
so:
navigator.battery.isReady.then(doFunThings)
--
Marcos Caceres
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0043.html
[[
> Rick, Chromium has a multi-process architecture, whereas Firefox in
> general keeps most things in a single process. Thus Firefox has the ability
> to implement many more things synchronously than Chromium does.
> Implementation experience based on a single vendor
>
There are two implementations. Firefox and Tizen.
> is not terribly valuable in guiding API surface, especially in questions
> of sync vs. async, and especially when that vendor is Firefox (the only
> single-process modern browser, from what I understand).
>
Battery status, especially a consolidated "virtual" status, doesn't change
depending on number of processes used by an application.
Rick
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0044.html
[[
> navigator.battery.isReady.then(doFunThings)
>
>
No, I don't want to be part of the discussion that lead to a boolean-ish
named thing that returns a promise.
Rick
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0045.html
[[
FirefoxOS/b2g is multi-process too, so we care a about not doing undue
sync IPC. We are doing some for the battery (see
https://mxr.mozilla.org/mozilla-central/source/hal/sandbox/PHal.ipdl#109).
I can run some timings if people are interested in knowing how long we
are blocked in these calls.
Fabrice
]]
http://lists.w3.org/Archives/Public/public-device-apis/2014Jul/0046.html
[[
I went ahead and did some basic timing measurements on both device
(FirefoxOS 1.4 [Fx30], ZTE Open) and desktop (Firefox 30, OSX 10.9.3). I
reviewed the timing method and results with Fabrice to confirm correctness.
https://gist.github.com/rwaldron/850590359d298e35bc61
Rick
]]
Resolved with (see http://lists.w3.org/Archives/Public/public-device-apis/2014Aug/0034.html) :
.. which I think has addressed itself by two major implementers (Google + Mozilla) implementing the promise-based API, and in addition positive signals from others (Cordova), see:
http://lists.w3.org/Archives/Public/public-device-apis/2014Aug/0023.html
http://lists.w3.org/Archives/Public/public-device-apis/2014Aug/0018.html
Display change log