Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Async APIs to abstract remote resources

75 views
Skip to first unread message

David Bruant

unread,
Feb 25, 2013, 8:14:26 AM2/25/13
to dev-w...@lists.mozilla.org, Julien Wajsberg, Mounir Lamouri, Richard Waldron
Hi,

I'll be reiterating here things that I've recently shared on the
dev-gaia mailing-list. Sorry for the repetition. At the end, I'll be
suggesting ideas and, upon agreement (if that happens), I'll be filing
bugs to fix the current situation.

There are a number of WebAPIs which enable interaction with a bunch of
remote resources (battery, FMRadio, DeviceStorage, etc.). Although these
resources are remote, some APIs give the illusion that these resources
are local. This illusion comes at some runtime cost (like runtime
performance or data reliability).

According to common practices in JavaScript, getting a property on an
object (which is local to the app) is a cheap operation. However,
"mozFMRadio.frequency" currently performs an IPC call, blocks the app
meanwhile and costs about 11 times what one would expect [1][2] (4.5ms
vs 0.4ms). This also makes reviewing app performance harder, because
what doesn't look like a bottleneck (getting properties out of an
object) may just be one.

It's been suggested that it was simply an implementation issue [3] and
that the platform could maintain the "local resource" illusion by being
optimized. This however comes at a cost somewhere, for instance, useless
inter-process communication to update a local cached value that may
never be read. Maintaining an illusion will always come at a price
somewhere. A price that may be detrimental for single apps performance
or the overall system performance.

I'd like to point out that history [4][5] taught us already that
abstracting remote resources with a sync API is a bad idea. And this is
not about bad implementation. It is about an API misdesign; a
mis-abstraction.
I feel we're in the same situation (but unlike localStorage we may have
some room to fix it).

Proposal:
1) Abstract remote as async
1.1) Whenever an API has a property which is not genuinely local, add a
get*() method which returns a DOMRequest (or hopefully soon a DOMFuture
[6])
So, for the FMRadio API, there would be a need for a getFrequency()
method (which by the way, resonates well with the already existing
setFrequency method) and a method for each current property which is not
1.2) (more controversial) get rid of the IPC blocking attribute. They
could be kept because they're convenient, but as said above, they make
perf review more complicated, because getting/setting a property isn't
expected to take several million CPU cycles.
Node.js found a sweet spot by allowing blocking sync APIs, by
post-fixing them with "Sync" [7]. That may be a good lead to follow.

2) Improve *change events to carry the modified value.
Currently, to get the new frequency, one has to do:

navigator.FMRadio.addEventListener('frequencychange', function(e){
// nothing useful in the 'e' argument +
var freq = navigator.FMRadio.frequency; // blocking IPC :-s
});

The situation would be hardly better with the async getFrequency method
because we'd still have to wait an equivalent amount of time before
being able to do something useful.
When I listen to the 'frequencychange' event, I rarely only want to be
notified. I mostly care about the new value. It takes almost the same
amount of work to notify me than notifiy me with the new value anyway.
One way to do that is to create a new event subclass per *change event.
In our case, have a:
FrequencyChangeEvent : Event{
readonly attribute double frequency;
}
It may be something that's hard to scale. I'm open to suggestion if some
feel it may result in too many Event subclasses.

Unless there are excellent reasons not to do 1.1 and 2, I'll file one
bug for the events and one bug for the async getters per concerned API
at the end of the week... and will reach out to standard bodies in
applicable cases as well I guess.

David

[1]
https://groups.google.com/d/msg/mozilla.dev.webapi/tLdpv5MkmUw/sgn6QZVW4HkJ
[2]
https://groups.google.com/d/msg/mozilla.dev.webapi/tLdpv5MkmUw/dBSrCL4MQrcJ
[3]
https://groups.google.com/d/msg/mozilla.dev.gaia/pcRc0XbIoPs/iGUM0lLGOe4J
[4]
https://blog.mozilla.org/tglek/2012/02/22/psa-dom-local-storage-considered-harmful/
[5]
https://hacks.mozilla.org/2012/03/there-is-no-simple-solution-for-local-storage/
[6] https://github.com/slightlyoff/DOMFuture
[7] http://nodejs.org/api/fs.html

Julien Wajsberg

unread,
Feb 25, 2013, 8:39:20 AM2/25/13
to David Bruant, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 25/02/2013 14:14, David Bruant a �crit :
>
> 2) Improve *change events to carry the modified value.
> Currently, to get the new frequency, one has to do:
>
> navigator.FMRadio.addEventListener('frequencychange', function(e){
> // nothing useful in the 'e' argument +
> var freq = navigator.FMRadio.frequency; // blocking IPC :-s
> });
>
> The situation would be hardly better with the async getFrequency method
> because we'd still have to wait an equivalent amount of time before
> being able to do something useful.
> When I listen to the 'frequencychange' event, I rarely only want to be
> notified. I mostly care about the new value. It takes almost the same
> amount of work to notify me than notifiy me with the new value anyway.
> One way to do that is to create a new event subclass per *change event.
> In our case, have a:
> FrequencyChangeEvent : Event{
> readonly attribute double frequency;
> }
> It may be something that's hard to scale. I'm open to suggestion if some
> feel it may result in too many Event subclasses.

AFAIK this is what a lot of other APIs already do:
ex: DeviceOrientation [1], DeviceMotion [2], all mouse events.

Geolocation [3] has two methods, both asynchronous: one to get one
value, one to be notified (and this one could be better implemented with
an event, but that's another story).

[1]
https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/deviceorientation
[2]
https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/devicemotion
[3] https://developer.mozilla.org/en-US/docs/Using_geolocation

Mounir Lamouri

unread,
Feb 26, 2013, 2:50:42 PM2/26/13
to dev-w...@lists.mozilla.org, Julien Wajsberg, David Bruant, Richard Waldron
On 25/02/13 13:14, David Bruant wrote:
> Hi,
>
> [...]
>
> Proposal:
> 1) Abstract remote as async
> 1.1) Whenever an API has a property which is not genuinely local, add a
> get*() method which returns a DOMRequest (or hopefully soon a DOMFuture
> [6])

We thought a lot about that and we decided that there was no interest to
make the Battery API asynchronous because it would add a level of
complexity for developers that seems useless.

Generally speaking, the question isn't as simple as "this information
can take time to be retrieved so we should make it async", it is a
balance between ease for developers and ability for user agents to make
the information virtually synchronous.

> 2) Improve *change events to carry the modified value.
> Currently, to get the new frequency, one has to do:
>
> navigator.FMRadio.addEventListener('frequencychange', function(e){
> // nothing useful in the 'e' argument +
> var freq = navigator.FMRadio.frequency; // blocking IPC :-s
> });

You are pointing a bug, not a problem in the API. as soon as an event is
sent because there is a frequency chance, calling
navigator.FMRadio.frequency should be fast and shouldn't do IPC calls.

Indeed, this is how some API work (like DeviceSensors) but they are
different because the API is all about events (you can't do
navigator.sensors.foo). FWIW, I do not really like that.
The Battery API was weirdly designed and very close to that in the past
and the hassle it would have been to use it wouldn't have worth it.

FWIW, that discussion already happened (a few times likely) in the DAP
WG and the DAP WG would be the best place to ask for changes. I would
recommend you to read the archives before though.

Cheers,
--
Mounir

David Bruant

unread,
Feb 26, 2013, 5:17:37 PM2/26/13
to Mounir Lamouri, dev-w...@lists.mozilla.org, Richard Waldron, Julien Wajsberg
Le 26/02/2013 20:50, Mounir Lamouri a écrit :
> On 25/02/13 13:14, David Bruant wrote:
>> Hi,
>>
>> [...]
>>
>> Proposal:
>> 1) Abstract remote as async
>> 1.1) Whenever an API has a property which is not genuinely local, add a
>> get*() method which returns a DOMRequest (or hopefully soon a DOMFuture
>> [6])
> We thought a lot about that and we decided that there was no interest to
> make the Battery API asynchronous because it would add a level of
> complexity for developers that seems useless.
You skipped that part, but I wrote "This also makes reviewing app
performance harder, because what doesn't look like a bottleneck (getting
properties out of an object) may just be one.".
Saying that getting a property is easier is a biased argument. Of course
the one-liner and the post on hacks.m.o are sexier this way, but when
your code is already hundreds of lines long, the difference between:
var freq = radio.frequency
// play with freq
and
radio.getFrequency().then(function(freq){
// play with freq
})
is blurred away.
You likely copy/pasted the code to get the frequency from MDN or the
gaia app or a prevous app anyway. Pragmatically speaking, this kind of
difference in APIs is negligeable when writing an app, mostly because
your focus is building the UI.

Also, if developer ease is the cause, why the asymmetry between getting
(sync&blocking) and setting (async)?
Rehashing previous arguments (that you skipped too!), but localStorage
was also designed with developer convenience in mind and a lot are
throwing rocks at it now, especially at Mozilla (see links in the
previous post). We should learn from history instead of reiterating it.

> Generally speaking, the question isn't as simple as "this information
> can take time to be retrieved so we should make it async", it is a
> balance between ease for developers and ability for user agents to make
> the information virtually synchronous.
Why not expose both versions as it is done in Node.js enabling the best
of both worlds?
People who want to draft something quickly use the sync blocking
version, people who don't want their startup time.

>> 2) Improve *change events to carry the modified value.
>> Currently, to get the new frequency, one has to do:
>>
>> navigator.FMRadio.addEventListener('frequencychange', function(e){
>> // nothing useful in the 'e' argument +
>> var freq = navigator.FMRadio.frequency; // blocking IPC :-s
>> });
> You are pointing a bug, not a problem in the API. as soon as an event is
> sent because there is a frequency chance, calling
> navigator.FMRadio.frequency should be fast and shouldn't do IPC calls.
I'm pointing 2 things. The blocking IPC call is halfway between an
implementation and API bug.
Not carrying the modified value in the event is a pure API bug. You
skipped that part from my previous post:
"When I listen to the 'frequencychange' event, I rarely only want to be
notified. I mostly care about the new value."

> Indeed, this is how some API work (like DeviceSensors) but they are
> different because the API is all about events (you can't do
> navigator.sensors.foo). FWIW, I do not really like that.
> The Battery API was weirdly designed and very close to that in the past
> and the hassle it would have been to use it wouldn't have worth it.
In my opinion, your sentence "FWIW, I do not really like that" captures
the essence of the debate we're having.
I'll spend some time on that here, because I feel it is and will be at
the heart of any API debate we will be having. I'll answer to you
because you wrote the words, but I don't mean to singularize you as a
person since I know you're not the only one thinking this way. Whenever
I'll write "you", it'll be less about you as a person than you as a C++
hacker.

Alex Russel wrote something very interesting about WebIDL a couple of
months ago [1] where he opposes those who write the JavaScript API specs
(who he describes as "C++ hackers") and those who use these APIs ("JS
developers").

Very much like natural languages, users of programming languages carry a
cultural bagage. What's easy to express in a language is not in another.
Some idioms of a language don't exist in another. Very much like natural
languages, if you only practice one language, reading another language
is complicated, very often less because of the very words, but more
because of the idioms, the culture around the language.
We'd love to think that we communicate after we think, but the opposite
is much more true: languages shape how we think. While in French, "on
prend une décision" ("one takes a decision"), like one chooses a path to
follow among a limited handful of choices, in English, "one makes a
decision", building it out of a combination of decision lego-like
pieces. The language we use shape how we think, shapes the culture of
the groups of people who use and work around the same language.

When I read your "FWIW, I do not really like that", what I understand is
"this is not how I do that in my culture and this is making me feel
uncomfortable". Just to be clear, I do not mean to blame you or point a
finger at you; I'm just sharing a feeling.
In my "culture" (JS devs), you have no idea how much I am happy with the
DeviceSensors and events all over the place. Values aren't stuck to a
given objects. Values fly around and I catch them by setting functions
here and there. The event loop protects me from race conditions (having
done some C in my life, this property has some gold to it). This API
fits how I use JavaScript very well.

2 other people from the JS culture (Julien and Rick) agreed that having
the changed value in the event is the natural way to do it. I feel
cultural bias should be put aside and this feedback should be heard.

> FWIW, that discussion already happened (a few times likely) in the DAP
> WG and the DAP WG would be the best place to ask for changes.
Are both cultures properly represented? ;-)
I'll post my concerns on the DAP WG list.

> I would recommend you to read the archives before though.
I will.

David

[1]
http://lists.w3.org/Archives/Public/public-script-coord/2012OctDec/0122.html

Julien Wajsberg

unread,
Feb 27, 2013, 5:31:00 AM2/27/13
to David Bruant, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 26/02/2013 23:17, David Bruant a écrit :

> 2 other people from the JS culture (Julien and Rick) agreed that having
> the changed value in the event is the natural way to do it. I feel
> cultural bias should be put aside and this feedback should be heard.

FWIW, I also like being able to get the value very easily on the object.
Both are useful, for different use cases, or different code styles.

Actually, in Mounir's proposition, we'd still be able to have it in the
event object: eg "event.target.frequency" or "this.frequency". This is
good enough for me, if this is fast of course. The assumption we need to
have here is that the object in event.target is "ready", ie accessing
any property is as fast as accessing a normal JS property.

Also, this scales well over the number of Web API we (want to) have.

--
Julien

David Bruant

unread,
Feb 27, 2013, 6:02:14 AM2/27/13
to Julien Wajsberg, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 11:31, Julien Wajsberg a écrit :
> Le 26/02/2013 23:17, David Bruant a écrit :
>
>> 2 other people from the JS culture (Julien and Rick) agreed that having
>> the changed value in the event is the natural way to do it. I feel
>> cultural bias should be put aside and this feedback should be heard.
> FWIW, I also like being able to get the value very easily on the object.
> Both are useful, for different use cases, or different code styles.
Agreed. An idea would be to have a blocking .frequency and non-blocking
async .getFrequency(). If we do have both (Node.js style with their
*Sync methods), all the cache+IPC update code can be thrown away
(because it potentially slows down the entire system for nothing!)

> Actually, in Mounir's proposition, we'd still be able to have it in the
> event object: eg "event.target.frequency" or "this.frequency". This is
> good enough for me, if this is fast of course.
From what I understand (correct me if I'm wrong), Mounir wrote that
when an event happens, the value in "navigator.FMRadio.frequency"
(starts with "navigator", not "event") should be already up-to-date and
quick to access. That's how the battery API works apparently. This is
the design Microsoft had chosen for there attachEvent method. The event
infos were in a global "event" property.

> The assumption we need to
> have here is that the object in event.target is "ready", ie accessing
> any property is as fast as accessing a normal JS property.
>
> Also, this scales well over the number of Web API we (want to) have.
If that's "event.target.frequency" instead of "event.frequency", I'll be
very happy too so long as the info is attached to the event and not a
global object

David

David Bruant

unread,
Feb 27, 2013, 7:07:44 AM2/27/13
to Julien Wajsberg, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 12:02, David Bruant a écrit :
> Le 27/02/2013 11:31, Julien Wajsberg a écrit :
>> Actually, in Mounir's proposition, we'd still be able to have it in the
>> event object: eg "event.target.frequency" or "this.frequency". This is
>> good enough for me, if this is fast of course.
> From what I understand (correct me if I'm wrong), Mounir wrote that
> when an event happens, the value in "navigator.FMRadio.frequency"
> (starts with "navigator", not "event")
What I had failed to understand was:
event.target === navigator.frequency
Twitter discussion happened [1][2] (translation is my own):
"event.target gets you the current frequency, not the one that triggered
the event. Your frequency can change between the time of the event and
the time you read the value".
And I could not agree more. Trouble can come if you're listening to an
*change event that's triggered twice very quickly and because of race
conditions, the value in both cases is the same. If your code relies on
the value being actually different, you have a bug that you really
didn't expect.
Let's dive into saying that such a bug may reveal itself only for some
implementations of the APIs, only in some devices which isn't good for
anyone.

David

[1] https://twitter.com/edas_live/status/306729729124339712
[2] https://twitter.com/edas_live/status/306729816797880321

Julien Wajsberg

unread,
Feb 27, 2013, 8:20:40 AM2/27/13
to David Bruant, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 13:07, David Bruant a écrit :
> Le 27/02/2013 12:02, David Bruant a écrit :
>> Le 27/02/2013 11:31, Julien Wajsberg a écrit :
>>> Actually, in Mounir's proposition, we'd still be able to have it in the
>>> event object: eg "event.target.frequency" or "this.frequency". This is
>>> good enough for me, if this is fast of course.
>> From what I understand (correct me if I'm wrong), Mounir wrote that
>> when an event happens, the value in "navigator.FMRadio.frequency"
>> (starts with "navigator", not "event")
> What I had failed to understand was:
> event.target === navigator.frequency
> Twitter discussion happened [1][2] (translation is my own):
> "event.target gets you the current frequency, not the one that triggered
> the event. Your frequency can change between the time of the event and
> the time you read the value".

> And I could not agree more. Trouble can come if you're listening to an
> *change event that's triggered twice very quickly and because of race
> conditions, the value in both cases is the same. If your code relies on
> the value being actually different, you have a bug that you really
> didn't expect.

I *think* we don't fire a new event if the previous one wasn't handled
yet (ie: the handler did not return yet). Is is true ?

I think the important for an app is to know the current value anyway, it
doesn't care about the previous values.

--
Julien

David Bruant

unread,
Feb 27, 2013, 8:52:01 AM2/27/13
to Julien Wajsberg, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
The implementation may be queuing values in the cache and pulling them
to trigger different events. If it does that, it might as well put the
value in as part of an event loop message [1]. That's just re-designing
an existing feature but exposing it awkwardly.

How many subtle implementation details are we going to discuss until
realizing that passing the changed value as part of the event is just a
simpler design?

Likewise for false local values. The best idea to implement some parts
of some APIs is per-app cached value and repeated IPC to update the
cache. And lazily start this process on first value retrieval... just to
get a bunch of values.
Isn't this the sign of over-engineering?
Nowhere else in the platform this mechanism was necessary apparently
Seriously, haven't we just passed the point where we should start
questioning the API instead of the implementation?

If not, when is this point?

> I think the important for an app is to know the current value anyway, it
> doesn't care about the previous values.
You may want to plot the different values in a graph or whatever. UI
research does that by recording mouse events and in these events, the
value of the coordinates are the ones at the time of event, not at the
time of property retrieval.
Frequency sounds stupid to plot, but battery could make a lot of sense.

David

[1] https://developer.mozilla.org/en-US/docs/JavaScript/Guide/EventLoop

Julien Wajsberg

unread,
Feb 27, 2013, 9:18:15 AM2/27/13
to David Bruant, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 14:52, David Bruant a écrit :
> Le 27/02/2013 14:20, Julien Wajsberg a écrit :
>> Le 27/02/2013 13:07, David Bruant a écrit :
>>> And I could not agree more. Trouble can come if you're listening to an
>>> *change event that's triggered twice very quickly and because of race
>>> conditions, the value in both cases is the same. If your code relies on
>>> the value being actually different, you have a bug that you really
>>> didn't expect.
>> I *think* we don't fire a new event if the previous one wasn't handled
>> yet (ie: the handler did not return yet). Is is true ?
> The implementation may be queuing values in the cache and pulling them
> to trigger different events. If it does that, it might as well put the
> value in as part of an event loop message [1]. That's just re-designing
> an existing feature but exposing it awkwardly.
>
> How many subtle implementation details are we going to discuss until
> realizing that passing the changed value as part of the event is just a
> simpler design?
>
> Likewise for false local values. The best idea to implement some parts
> of some APIs is per-app cached value and repeated IPC to update the
> cache. And lazily start this process on first value retrieval... just to
> get a bunch of values.


I guess that will be done anyway: the DOM object is always a
"reflection" of what happens internally.


> Isn't this the sign of over-engineering?
> Nowhere else in the platform this mechanism was necessary apparently.


Are you sure ?

- battery API
- online API (granted we also have 2 events here that carry both bits of
information, but we usually bind them to the same function that checks
navigator.onLine )
- page visibility API [1]
- heck, even the scroll event is done like that !

[1]
https://developer.mozilla.org/en-US/docs/Mozilla_Event_Reference/visibilitychange

Others API are done the other way around (mousemove event, geolocation,
proximity API).


> Seriously, haven't we just passed the point where we should start
> questioning the API instead of the implementation?

Well, I think we are ?

>
>> I think the important for an app is to know the current value anyway, it
>> doesn't care about the previous values.
> You may want to plot the different values in a graph or whatever. UI
> research does that by recording mouse events and in these events, the
> value of the coordinates are the ones at the time of event, not at the
> time of property retrieval.
> Frequency sounds stupid to plot, but battery could make a lot of sense.

Well, I doubt the difference between both battery values (the one when
the event is triggered, and the one when you'll query the object in the
handler) is meaningful for the battery level.

--
Julien

David Bruant

unread,
Feb 27, 2013, 9:46:52 AM2/27/13
to Julien Wajsberg, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 15:18, Julien Wajsberg a écrit :
> Le 27/02/2013 14:52, David Bruant a écrit :
>> Le 27/02/2013 14:20, Julien Wajsberg a écrit :
>>> Le 27/02/2013 13:07, David Bruant a écrit :
>>>> And I could not agree more. Trouble can come if you're listening to an
>>>> *change event that's triggered twice very quickly and because of race
>>>> conditions, the value in both cases is the same. If your code relies on
>>>> the value being actually different, you have a bug that you really
>>>> didn't expect.
>>> I *think* we don't fire a new event if the previous one wasn't handled
>>> yet (ie: the handler did not return yet). Is is true ?
>> The implementation may be queuing values in the cache and pulling them
>> to trigger different events. If it does that, it might as well put the
>> value in as part of an event loop message [1]. That's just re-designing
>> an existing feature but exposing it awkwardly.
>>
>> How many subtle implementation details are we going to discuss until
>> realizing that passing the changed value as part of the event is just a
>> simpler design?
>>
>> Likewise for false local values. The best idea to implement some parts
>> of some APIs is per-app cached value and repeated IPC to update the
>> cache. And lazily start this process on first value retrieval... just to
>> get a bunch of values.
>
> I guess that will be done anyway: the DOM object is always a
> "reflection" of what happens internally.
The concern isn't what the object is, but rather how you retrieve the
related information.
If the only API you have is an async API, then the implementation
doesn't need to go through per-app cache + IPC-based updates. The
implementation just returns a DOMRequest/DOMFuture quickly, does the IPC
*only once* because the app requested it and tells you when the value is
ready.
I emphasis "only once", because currently, cached values are updated in
the background and who knows how much that costs.
IPC is necessary to transport the value from the remote resource to the
app, that's will always be necessary. The cache+update isn't necessary.

If you have both sync & async à la Node.js, then, making the sync
version slow is fine.

The "only blocking sync API" case is the one that forces a complex
implementation.

>> Isn't this the sign of over-engineering?
>> Nowhere else in the platform this mechanism was necessary apparently.
> Are you sure ?
I spoke too fast on that one.

>> Seriously, haven't we just passed the point where we should start
>> questioning the API instead of the implementation?
> Well, I think we are ?
From implementors, I've only read points about implementation so far.
But we are indeed. Thanks :-)

>>> I think the important for an app is to know the current value anyway, it
>>> doesn't care about the previous values.
>> You may want to plot the different values in a graph or whatever. UI
>> research does that by recording mouse events and in these events, the
>> value of the coordinates are the ones at the time of event, not at the
>> time of property retrieval.
>> Frequency sounds stupid to plot, but battery could make a lot of sense.
> Well, I doubt the difference between both battery values (the one when
> the event is triggered, and the one when you'll query the object in the
> handler) is meaningful for the battery level.
If you want to study the battery (not energy) consumption of an app,
it's very possible that your app runs a lot of code and that a lot of
time passes between 2 levelchange events. Reading the value at time of
value retrieval leads to inaccurate measurements, inaccurate
conclusions, inaccurate decisions.
If you have a value in the event, you can match the event.timestamp and
the battery level.

David

Julien Wajsberg

unread,
Feb 27, 2013, 10:11:38 AM2/27/13
to David Bruant, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 15:46, David Bruant a écrit :

> I emphasis "only once", because currently, cached values are updated in
> the background and who knows how much that costs.


That's really the only valid point here. Eg what happens if a webpage
never uses the Battery API ? Is the object still updated in real time ?
Is it only the case for APIs with small event frequency ?


> IPC is necessary to transport the value from the remote resource to the
> app, that's will always be necessary. The cache+update isn't necessary.
>
> If you have both sync & async à la Node.js, then, making the sync
> version slow is fine.

Nobody ever wants a slow blocking sync API.

>
> The "only blocking sync API" case is the one that forces a complex
> implementation.

Maybe it's the only one that makes sense for some APIs.


>>>> I think the important for an app is to know the current value
>>>> anyway, it
>>>> doesn't care about the previous values.
>>> You may want to plot the different values in a graph or whatever. UI
>>> research does that by recording mouse events and in these events, the
>>> value of the coordinates are the ones at the time of event, not at the
>>> time of property retrieval.
>>> Frequency sounds stupid to plot, but battery could make a lot of sense.
>> Well, I doubt the difference between both battery values (the one when
>> the event is triggered, and the one when you'll query the object in the
>> handler) is meaningful for the battery level.
> If you want to study the battery (not energy) consumption of an app,
> it's very possible that your app runs a lot of code and that a lot of
> time passes between 2 levelchange events. Reading the value at time of
> value retrieval leads to inaccurate measurements, inaccurate
> conclusions, inaccurate decisions.
> If you have a value in the event, you can match the event.timestamp and
> the battery level.

Really, you're not making a point at all here. I think your use case is
not realistic at all.

Some APIs really need this (devicemotion is one of them, mousemove too),
and they are implemented like you want. Some don't need this, and they
are not.

I think this is fine, and we can fix any performance issue that can be
found. We can also change some API if there is a real use case. A
general discussion is not what we need, because there is not one unique
way to implement all APIs.

--
Julien

David Bruant

unread,
Feb 27, 2013, 11:20:28 AM2/27/13
to Julien Wajsberg, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 16:11, Julien Wajsberg a écrit :
> Le 27/02/2013 15:46, David Bruant a écrit :
>> I emphasis "only once", because currently, cached values are updated in
>> the background and who knows how much that costs.
> That's really the only valid point here.
That's the only one I'm making regarding the false local value case...
hmm... No. The only point I'm making is that mis-abstraction leads to
issues somewhere. I've just pointed at the issue in the current
implementation. But I feel fixing it will have another issue somewhere.

> Eg what happens if a webpage never uses the Battery API ?
The best thing I can think of is setting up this on first battery.level
(or whatever property) access. It expresses "some" interest in the
value, so the engine can optimistically consider the value will be
retrieved often. That's an optimistic assumption, not an absolute truth.

> Is the object still updated in real time ?
That's the only way the API can work correctly I can think of.

> Is it only the case for APIs with small event frequency ?
10 small event frequency make one big event frequency?
If several apps have their cached value updated, even at low frequency,
this adds up.
Whether it's several small frequency events or one small frequency event
listened by several people, this doesn't scale up.


>> IPC is necessary to transport the value from the remote resource to the
>> app, that's will always be necessary. The cache+update isn't necessary.
>>
>> If you have both sync & async à la Node.js, then, making the sync
>> version slow is fine.
> Nobody ever wants a slow blocking sync API.
Except for the sync version of the IndexedDB API in workers that Mozilla
wants [1].
And except for Node.js which made the conscious choice to provide I/O
APIs in 2 flavors [2] The *Sync version being known to be slow (but
convenient because leads to write sequential code. Promises enable
async+sequential but that's a different topic)

A slow blocking sync API is acceptable as long as there is a faster
alternative.

>> The "only blocking sync API" case is the one that forces a complex
>> implementation.
> Maybe it's the only one that makes sense for some APIs.
Node.js succeeded in proving that this sentence is false.
What is the problem with having 2 points of access for the same property?

>>>>> I think the important for an app is to know the current value
>>>>> anyway, it
>>>>> doesn't care about the previous values.
>>>> You may want to plot the different values in a graph or whatever. UI
>>>> research does that by recording mouse events and in these events, the
>>>> value of the coordinates are the ones at the time of event, not at the
>>>> time of property retrieval.
>>>> Frequency sounds stupid to plot, but battery could make a lot of sense.
>>> Well, I doubt the difference between both battery values (the one when
>>> the event is triggered, and the one when you'll query the object in the
>>> handler) is meaningful for the battery level.
>> If you want to study the battery (not energy) consumption of an app,
>> it's very possible that your app runs a lot of code and that a lot of
>> time passes between 2 levelchange events. Reading the value at time of
>> value retrieval leads to inaccurate measurements, inaccurate
>> conclusions, inaccurate decisions.
>> If you have a value in the event, you can match the event.timestamp and
>> the battery level.
> Really, you're not making a point at all here. I think your use case is
> not realistic at all.
Measuring accurately (in time) the battery usage of a
CPU/graphics-intensive app over time is unrealistic?

> Some APIs really need this (devicemotion is one of them, mousemove too),
> and they are implemented like you want. Some don't need this, and they
> are not.
What's the criteria? Is such a per-API discussion worthwhile?

> I think this is fine, and we can fix any performance issue that can be
> found.
This is not really about performance, but mis-abstraction. If you want
performance, just pick the value at app init and don't update it. This
implementation solution has no performance issue whatsoever.
Hopefully, you'll notice a different kind of issue (that's what I meant
at the top of this post).

The current implementation of the current API has reached an acceptable
balance of not costing too much in terms of information loss and
performance. It does cost something anyway. It is acceptable now. Will
it bite later?

A different API could be implemented in such a way that it has *no*
information loss nor performance cost and would be easier to implement.

> We can also change some API if there is a real use case. A
> general discussion is not what we need, because there is not one unique
> way to implement all APIs.
I'm not worried about ways to implement APIs. I'm concerned about APIs
design.

Even for the implementors benefit should the APIs be made easier. There
are apparently issues with resources in testing [3]. How confident is
everyone in the cache+IPC update system? What about designing APIs which
just reuse existing mechanisms (event loop)?
I feel it makes sense even at the purely engineering level to design
APIs that'll be easier to implement.

David

[1] http://lists.w3.org/Archives/Public/public-webapps/2012JulSep/0648.html
[2] http://nodejs.org/api/fs.html
[3]
https://groups.google.com/d/msg/mozilla.dev.webapi/AMOyMCZ_vSQ/yW0gn1rm3hMJ

Julien Wajsberg

unread,
Feb 28, 2013, 5:33:27 AM2/28/13
to David Bruant, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 27/02/2013 17:20, David Bruant a écrit :
>
> A slow blocking sync API is acceptable as long as there is a faster
> alternative.

It stroke me this morning that the asynchronous API will not be faster.
It will merely be non-blocking, but otherwise it will still need to do
the same operations.

Being fast actually involves caching, and so why having an asynchronous
API in the first place if we cache the value anyway ?

--
Julien

David Bruant

unread,
Feb 28, 2013, 7:48:39 AM2/28/13
to Julien Wajsberg, dev-w...@lists.mozilla.org, Mounir Lamouri, Richard Waldron
Le 28/02/2013 11:33, Julien Wajsberg a écrit :
> Le 27/02/2013 17:20, David Bruant a écrit :
>> A slow blocking sync API is acceptable as long as there is a faster
>> alternative.
> It stroke me this morning that the asynchronous API will not be faster.
That came out really wrong. It is indeed not faster at all, not even in
the 2 examples I had provided.
I just should have said that slow blocking sync is acceptable when there
is an "async non-blocking" alternative.

> It will merely be non-blocking, but otherwise it will still need to do
> the same operations.
>
> Being fast actually involves caching, and so why having an asynchronous
> API in the first place if we cache the value anyway ?
Because a manual cache (and manual update) does not involve useless
background work. If you went the length of creating your own cache, you
really want it, so you're paying the cost for something you want.
Currently a cache is set up on first access (?) whether you really want
it or not.

Again, what's the problem with exposing both a sync and an async version?


On the benefit side, we have saving one line [1] out of apps that makes
hundreds of lines [2].
On the downsides, we have bloating every single FirefoxOS phone running
with useless background work.
What should be done looks obvious to me, but I have apparently failed to
convince anyone else. This discussion is going circles, wasting
everyone's time, so I'll stop.
I'm thankful to the people who've participated and invested time in the
discussion and I apologize for the noise on the list.

Thanks,

David

[1]
https://groups.google.com/d/msg/mozilla.dev.webapi/H-bKMtn_XUI/xwtgmKk9VeMJ
[2] https://github.com/mozilla-b2g/gaia/blob/master/apps/fm/js/fm.js
0 new messages