dart:html should support async AND sync measuring APIs

44 views
Skip to first unread message

John Evans

unread,
Jan 7, 2012, 7:32:52 AM1/7/12
to General Dart Discussion
Bob Nystrom made a great statement regarding dart:html on the G+
hangout yesterday (btw, thanks Seth, Bob, and team - it was great). I
paraphrase: "dart:html should be at least as easy to work with as
dart:dom, if not easier'.

Understanding that getting measurement properties from the DOM causes
layout overhead, it makes sense that in many, I'll say "atomic"
situations, you can do this asynchronously. You can even do a bunch
of measurements asynchronously and then wait in requestLayoutFrame().
However, in more complex situations where you have layered flow
control, all needing measurements, and where you may also have other
asynchronous callbacks performing measurements, using the async model
becomes, in my opinion untenable. Can this scenario be solved? Yes,
but there is a great deal more heavy lifting involved just to get at
these metrics, and this is where I think it goes counter to the spirit
of what dart:html is all about.

I don't have an example of this anymore because I ripped it all out
and moved back to dart:dom in my project a while ago. I've got async
in Grid.dart and FrameworkElement.dart back at this commit
08581883cf9f2874ae2fe0731a0140f34c50935d if you really want to dig in
(git://github.com/LUCA-Studios-LLC/LUCA-UI-Framework-for-Dart.git).

That scenario may turn out to be just a corner case, but I suspect as
more and more larger-scale client-side apps are written, it will come
up more often. I suggest that the Dart team get ahead of it, by
simply exposing the synchronous measurements - giving developers the
choice of which way to go based on application requirements.

I'm aware that there may be performance issues with the CSS3
transforms when doing sync layouts, but I think this too is manageable
(vs async), especially in a large-scale apps where all of that is
tightly managed anyway.

I would also speculate that async measuring may prove a barrier to
entry for the javascript community at-large, when they've been used to
sync measuring for so long.

Joao Pedrosa

unread,
Jan 7, 2012, 8:49:06 AM1/7/12
to General Dart Discussion
Hi,
Nice write-up. I for one have decided to go with dart:dom for my own
library even without giving the dart:html a try, just from reading
about it on this list. As I was converting the library from JavaScript
to Dart I had to pay attention to a lot of other concerns already so I
tried to keep some of it unsurprising. Among other things, I had to
remove the dependency on the Prototype JavaScript library which wasn't
too hard in the end.

Async may be helpful in some cases, but we already have to pay
attention to a lot of events and synchronous code.

Cheers,
Joao

Jacob Richman

unread,
Jan 10, 2012, 2:16:47 AM1/10/12
to Joao Pedrosa, General Dart Discussion, John
John, thanks for the clear writeup.  We have a new solution that addresses the pain points you describe while retaining the measurement batching benefits of the current solution.  With the new design, complex measurement cases with tricky control flow can now be handle cleanly because we have switched the abstraction from forcing single measurement calls to be async to forcing blocks of code that contain arbitrary amounts of measurement but no DOM manipulation to be async.

With the new design you make a single call (requestMeasurementFrame) which executes a callback in context where sync measurement is allowed but DOM manipulation is prohibited.  That callback can optionally return another callback which is executed in the default context where sync measurement is prohibited and DOM manipulation is allowed.
Asserts fire when measurement is performed in the wrong context when running in developer mode but do not fire in production mode which insures that checking for calls made in the wrong context will not slow down your production app.
With the new solution, as long as you don't want to tightly interleave measurement and dom manipulation the code is a little verbose but easy to write and easy to follow unlike the previous async code.  You shouldn't be tightly interleaving measurement and layout anyway if you want good performance.

Here's an early preview of what the new API will look like:
The CL also contains some partially written code showing how existing samples have to be modified to use the new API.
So far the pattern that I've found works well with the new API is to avoid calling requestMeasurementFrame from within helper methods that need to perform measurement and instead just assert if they are not called from within requestMeasurementFrame.  Instead, call requestMeasurementFrame from within each method that calls the helper methods that perform the actual measurement.  This is consistent with the new dart:html APIs where measurement methods assert if called outside of a requestMeasurementFrame callback.

We are open to other suggestions for the name of requestMeasurementFrame. Its just the first decent name we could think of.

-Jacob

John Evans

unread,
Jan 10, 2012, 9:50:13 PM1/10/12
to General Dart Discussion
I think this is a good approach, and I'll be the first one to take it
up as soon as it hits CI.

A few things about this keep gnawing at me though. You don't need to
answer these questions - they are just on my "to research" list:

What is it about browser architecture that requires a "high cost"
layout in order to read the current measurement of an element?

How does the browser engine render the element at a certain size in
the box model unless it has some concrete measurement value stored
somewhere?

Jacob Richman

unread,
Jan 10, 2012, 10:17:09 PM1/10/12
to John Evans, General Dart Discussion
Here's some background information on browser layout:


Answers inline.

On Tue, Jan 10, 2012 at 6:50 PM, John Evans <pru...@gmail.com> wrote:
I think this is a good approach, and I'll be the first one to take it
up as soon as it hits CI.

A few things about this keep gnawing at me though.  You don't need to
answer these questions - they are just on my "to research" list:

What is it about browser architecture that requires a "high cost"
layout in order to read the current measurement of an element?
Because layouts typically aren't incremental.  When something changes the whole document layout often needs be computed before the size for any element is available.
 
How does the browser engine render the element at a certain size in
the box model unless it has some concrete measurement value stored
somewhere?
If the browser has already rendered the current DOM, then layout measurements are virtually free. The issue is that if the DOM has been modified in virtually any way since the last time it rendered .  In that case, requesting layout will cause a lot of work to happen which will be largely wasted if you later modify the DOM further invalidating the work you just did.

-Jacob 

John Evans

unread,
Jan 12, 2012, 9:28:24 AM1/12/12
to mi...@dartlang.org, John Evans
I 100% get it now.  Thanks for the reference material; really helped.

I can see when css3 animations are added in to the mix, this becomes vitally important.
Reply all
Reply to author
Forward
0 new messages