<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-14995055</id><updated>2012-01-02T22:14:35.220-05:00</updated><title type='text'>as simple as possible, but no simpler</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.j15r.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>23</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-14995055.post-2928355548056443624</id><published>2011-12-15T15:52:00.000-05:00</published><updated>2011-12-16T16:06:58.550-05:00</updated><title type='text'>Box2D as a Measure of Runtime Performance</title><content type='html'>&lt;p&gt;For those unfamiliar with it, &lt;a href="http://box2d.org/"&gt;Box2D&lt;/a&gt; is a great 2D physics library written by
Erin Catto, which is at the core of a large number of casual games on consoles
and mobile devices. &lt;a href="http://chrome.angrybirds.com/"&gt;Angry Birds&lt;/a&gt; is one you might have heard of, but there are
many, many others.&lt;/p&gt;

&lt;p&gt;It's also not a simple library by any means. When porting Angry Birds to HTML5,
we found that in some cases Box2D performance could be the limiting factor in
the game's frame-rate (on the more complex levels). It turns out this little
library is doing a &lt;em&gt;lot&lt;/em&gt; of work under the hood. And the work it's doing isn't
limited to any one tight loop or hotspot. Rather, its work is distributed all
over the place -- matrix and vector math, creation of lots of small objects,
and general object-oriented logic distributed over a complex code base.&lt;/p&gt;

&lt;h2&gt;Motivation&lt;/h2&gt;

&lt;p&gt;Box2d makes a great general benchmark -- it's a bottleneck on real-world apps,
and there's no one thing that a VM or compiler can optimize to "fix it". It
also has the nice property that it's been ported to lots of different platforms
-- the original is written in C++, and it's been ported to ActionScript, Java,
Javascript, and several other systems.  So I took it upon myself to put
together a little benchmark that measures the time it takes to simulate one
frame of a reasonably complex Box2D world.&lt;/p&gt;

&lt;p&gt;The goal of this little experiment is not to add fuel to the flames of the
Internet's already-tiresome "Compiler and VM Wars" -- rather, my intention is
to get some hard data on what behavior real-world performance-sensitive code
can actually expect to see in practice on various platforms. Measuring the
performance of virtual machines in isolation is particularly &lt;a href="http://blog.mrale.ph/post/12396216081/the-trap-of-the-performance-sweet-spot"&gt;tricky&lt;/a&gt;, but this
benchmark has the nice property that, if a VM or compiler improves it, then
real-world problems are actually solved in the wild, and everyone wins.&lt;/p&gt;

&lt;h2&gt;The Platforms&lt;/h2&gt;

&lt;p&gt;My intention is to measure the performance of various &lt;em&gt;platforms&lt;/em&gt;, not
particular Box2D ports. The ports themselves necessarily vary somewhat from
one-another, but they should still be broadly equivalent. The reason Javascript
VMs are represented four times in this list is that I wanted to make sure that
we compared Javascript VMs, at their best, to the JVM, NaCl, and native code.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Native&lt;/em&gt; : This is the standard Box2D code, compiled via gcc or clang/llvm
(the latter on my test machine, as described below).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;NaCl&lt;/em&gt; : The same code, compiled via the NaCl SDK's custom gcc build, and
running within Chrome.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Java&lt;/em&gt; : The JRE (1.6), as currently shipped by Apple on Mac OS 10.6.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Box2D-web&lt;/em&gt; : The hand-written &lt;a href="http://code.google.com/p/box2dweb/"&gt;Javascript Box2D port&lt;/a&gt;, on various
browsers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Emscripten&lt;/em&gt; : The original C++ code, compiled via &lt;a href="https://github.com/kripken/emscripten"&gt;Emscripten&lt;/a&gt; to
Javascript.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Mandreel&lt;/em&gt; : The original C++ code, compiled via &lt;a href="http://mandreel.com/"&gt;Mandreel&lt;/a&gt; to Javascript.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;GwtBox2D&lt;/em&gt; : The Java port, compiled via GWT to Javascript. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The Test&lt;/h2&gt;

&lt;b&gt;World&lt;/b&gt;

&lt;p&gt;Picking the right world structure for this kind of benchmark is a bit tricky,
because it needs to have the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A high per-frame running time.&lt;/li&gt;
&lt;li&gt;Not settle quickly: simulations that settle eventually stop doing work,
as the physics engine skips calculations for settled objects.&lt;/li&gt;
&lt;li&gt;Stable: Subtle variations in the behavior of floating-point math can cause
the behavior on different VMs to diverge badly, invalidating comparisons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I eventually settled on a simple pyramid of boxes with 40 boxes at the base,
for a total of about 800 boxes. I manually verified that this simulation is
stable on all the systems tested, and that it doesn't settle within the number
of frames simulated for each test. It takes at least 3-4ms to simulate in
native code, and only gets slower from there, so the running time is sufficient
to avoid problems with timer resolution.&lt;/p&gt;

&lt;b&gt;Code&lt;/b&gt;

&lt;p&gt;All the test code is available on &lt;a href="http://github.com/joelgwebber/bench2d"&gt;GitHub&lt;/a&gt;. Some of it requires a bit of care
and feeding to get running (especially the C++ version), but should allow you
to reproduce these results if so desired. There are also copies of the Mandreel
and Emscripten Javascript output checked in, so you won't have to go through
the pain of building those yourself.&lt;/p&gt;

&lt;b&gt;Test System&lt;/b&gt;

&lt;p&gt;I used my MacBook Pro 2.53 GHz Intel Core i5 as a test machine. It seems a
fairly middle-of-the road machine (maybe a bit on the fast side for a laptop).
As always, your mileage may vary.&lt;/p&gt;

&lt;h2&gt;Data&lt;/h2&gt;

&lt;p&gt;The raw data I collected is in the following &lt;a href="https://docs.google.com/spreadsheet/ccc?key=0Ag3_0ZPxr2HrdEdoUy1RVDQtX2k3a0ZISnRiZVZBaEE"&gt;spreadsheet&lt;/a&gt;. I ran each test
several times, to mitigate spikes and hiccups that might be caused by other
activity, and to give each system a fair chance. Each run warms up over 64
frames, and then runs for 256 frames -- I've confirmed that the simulation is
stable over this duration on all the platforms under test.&lt;/p&gt;

&lt;p&gt;First, let's look at all the results together, on a log-scale graph:&lt;/p&gt;

&lt;script src="//ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js" type="text/javascript"&gt; {"dataSourceUrl":"//docs.google.com/spreadsheet/tq?key=0Ag3_0ZPxr2HrdEdoUy1RVDQtX2k3a0ZISnRiZVZBaEE&amp;transpose=0&amp;headers=1&amp;merge=COLS&amp;range=B1%3AB257%2CC1%3AC257%2CD1%3AD257%2CE1%3AE257%2CF1%3AF257%2CG1%3AG257%2CH1%3AH257%2CI1%3AI257%2CJ1%3AJ257%2CK1%3AK257&amp;gid=0&amp;pub=1","options":{"reverseCategories":false,"titleX":"samples","pointSize":0,"backgroundColor":"#FFFFFF","lineWidth":2,"logScale":true,"hAxis":{"maxAlternations":1},"hasLabelsColumn":false,"vAxes":[{"title":"ms / frame","minValue":0,"viewWindowMode":"pretty","viewWindow":{"min":0,"max":150},"maxValue":150},{"viewWindowMode":"pretty","viewWindow":{}}],"title":"Box2D Performance (All, Log Scale)","interpolateNulls":false,"legend":"right","reverseAxis":false,"width":800,"height":600},"state":{},"view":"{\"columns\":[0,1,2,3,4,5,6,7,8,9]}","chartType":"LineChart","chartName":"Chart 1"} &lt;/script&gt;

&lt;p&gt;The first thing you'll notice is that there are three clusters of results,
centered roughly around 5ms, 10ms, and 100ms. These clusters are associated
with native code, the JVM, and Javascript VMs.&lt;/p&gt;

&lt;p&gt;Now let's compare the best of the best of each of these three groups.&lt;/p&gt;

&lt;script src="//ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js" type="text/javascript"&gt; {"dataSourceUrl":"//docs.google.com/spreadsheet/tq?key=0Ag3_0ZPxr2HrdEdoUy1RVDQtX2k3a0ZISnRiZVZBaEE&amp;transpose=0&amp;headers=1&amp;merge=COLS&amp;range=B1%3AB257%2CD1%3AD257%2CJ1%3AJ257&amp;gid=0&amp;pub=1","options":{"reverseCategories":false,"titleX":"samples","pointSize":0,"backgroundColor":"#FFFFFF","width":800,"lineWidth":2,"logScale":false,"hAxis":{"maxAlternations":1},"hasLabelsColumn":false,"vAxes":[{"title":"ms / frame","minValue":0,"viewWindowMode":"pretty","viewWindow":{"min":0,"max":0},"maxValue":0},{"viewWindowMode":"pretty","viewWindow":{}}],"title":"Box2D Performance (VMs vs. Native)","height":600,"interpolateNulls":false,"legend":"right","reverseAxis":false},"state":{},"view":"{\"columns\":[0,1,2]}","chartType":"LineChart","chartName":"Chart 1"} &lt;/script&gt;

&lt;p&gt;This is similar to the first graph, except that we've removed the noise of NaCl
(which is within 20-30% of raw native performance) and all but the best of the
various Javascript approaches. This looks a bit better for Javascript, clocking
in at a mean of around 50ms (interestingly, this number is achieved by the
Mandreel C++ cross-compiler running on Chrome 17; more on this below).&lt;/p&gt;

&lt;h2&gt;Analysis&lt;/h2&gt;

&lt;p&gt;Looking at the last graph above, I believe the most important observation is
that, while Javascript implementations have improved drastically in recent
years, the best result achieved by any Javascript implementation is still more
than an order-of-magnitude slower than native code. This is perhaps an
unsurprising result to many, but some have begun suggesting that modern
Javascript VMs are "nearing native performance". While this may be true for
some workloads, they still have a long way to go in this case.&lt;/p&gt;

&lt;p&gt;This also demonstrates that native code compiled via NaCl stays within 20-30%
of the performance of un-sandboxed native code, which is in line with what I've
been told to expect.&lt;/p&gt;

&lt;p&gt;Finally, it's somewhat interesting to see that the JVM is running 3x slower
than native code. I've been told, anecdotally, that OpenJDK on Mac OS X is
producing numbers closer to 6ms/frame, which would be ~50-60% slower than
native, but I need to confirm this.  I don't think it can be proven, but I
suspect the JVM's performance can be taken as a rough lower-bound on what one
can expect from &lt;em&gt;any&lt;/em&gt; dynamic VM.  Thus, Javascript VM implementors can take
the JVM's performance as a reasonable target to shoot for.&lt;/p&gt;

&lt;h2&gt;Appendix: Javascript Implementations and Compilers&lt;/h2&gt;

&lt;p&gt;While it wasn't a primary goal of these benchmarks, they do give some
interesting data about Javascript VMs, and the various compilers that use
Javascript as a target language.&lt;/p&gt;

&lt;p&gt;The following is a graph of the Javascript VMs in Chrome, Safari, Firefox,
and Opera (IE9's Chakra VM is not yet included because it seems that Box2D-Web
is using Javascript properties, which it doesn't support yet).&lt;/p&gt;

&lt;script src="//ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js" type="text/javascript"&gt; {"dataSourceUrl":"//docs.google.com/spreadsheet/tq?key=0Ag3_0ZPxr2HrdEdoUy1RVDQtX2k3a0ZISnRiZVZBaEE&amp;transpose=0&amp;headers=1&amp;merge=COLS&amp;range=E1%3AE257%2CF1%3AF257%2CG1%3AG257%2CH1%3AH257&amp;gid=0&amp;pub=1","options":{"reverseCategories":false,"titleX":"samples","pointSize":0,"backgroundColor":"#FFFFFF","lineWidth":2,"logScale":false,"hAxis":{"maxAlternations":1},"hasLabelsColumn":false,"vAxes":[{"title":"ms / frame","minValue":0,"viewWindowMode":"pretty","viewWindow":{"min":0,"max":150},"maxValue":150},{"viewWindowMode":"pretty","viewWindow":{}}],"title":"Box2D Performance (Javascript VMs)","interpolateNulls":false,"legend":"right","reverseAxis":false,"width":800,"height":600},"state":{},"view":"{\"columns\":[0,1,2,3]}","chartType":"LineChart","chartName":"Chart 1"} &lt;/script&gt;

&lt;p&gt;First off, all the VMs tested are well within 3x of each other, which is
wonderful, because wildly variant performance across browsers would make it
exceedingly difficult to depend upon them for any heavy lifting. V8 and JSCore
are quite close to one-another, but JSCore has an edge in variance. It's not
immediately obvious what's causing this, but GC pauses are a likely culprit
given the regularly-periodic spikes we see in this graph.&lt;/p&gt;

&lt;p&gt;Now we move to the various Javascript compilers. Here we have Box2D-Web
(representing "raw" Javascript), Emscripten, Mandreel, and GWT (Closure
Compiler should give performance roughly in line with "raw" Javacript on any
modern Javascript VM).&lt;/p&gt;

&lt;script src="//ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js" type="text/javascript"&gt; {"dataSourceUrl":"//docs.google.com/spreadsheet/tq?key=0Ag3_0ZPxr2HrdEdoUy1RVDQtX2k3a0ZISnRiZVZBaEE&amp;transpose=0&amp;headers=1&amp;merge=COLS&amp;range=F1%3AF257%2CI1%3AI257%2CJ1%3AJ257%2CK1%3AK257&amp;gid=0&amp;pub=1","options":{"reverseCategories":false,"titleX":"samples","pointSize":0,"backgroundColor":"#FFFFFF","lineWidth":2,"logScale":false,"hAxis":{"maxAlternations":1},"hasLabelsColumn":false,"vAxes":[{"title":"ms / frame","minValue":0,"viewWindowMode":"pretty","viewWindow":{"min":0,"max":0},"maxValue":0},{"viewWindowMode":"pretty","viewWindow":{}}],"title":"Box2D Performance (JS Compilers)","interpolateNulls":false,"legend":"right","reverseAxis":false,"width":800,"height":600},"state":{},"view":"{\"columns\":[0,1,2,3]}","chartType":"LineChart","chartName":"Chart 1"} &lt;/script&gt;

&lt;p&gt;The real shocker here is that Mandreel outperforms all the others fairly
consistently, given that it's translating C++ to Javascript (!). Note that the
Emscripten results are not as good as they could be -- the author is currently
finishing up a new optimizer.  I also believe the GWT compiler should be doing
a better job than it is; there are a couple likely culprits in the compiled
output involving static initializers and array initialization overhead. It
should be possible to optimize these out and improve the results.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Note: See the update below about Emscripten performance&lt;/i&gt;&lt;/p&gt;

&lt;h2&gt;Caveats&lt;/h2&gt;

&lt;p&gt;As with all benchmarks, especially ones as fuzzy as this, there are a lot of
caveats.&lt;/p&gt;

&lt;b&gt;The code's not identical&lt;/b&gt;

&lt;p&gt;These are all &lt;em&gt;ports&lt;/em&gt; of the same C++ source code, so by their nature they must
vary from one another. It may be the case that a particular port is unfairly
negatively biased, because of particular idioms used in the code. If you
suspect this is the case, please say so and preferably offer a patch to the
maintainer. These aren't being used in the same way as, e.g., the V8 or
Kraken benchmarks, so it's entirely fair to optimize the code to get better
numbers.&lt;/p&gt;

&lt;b&gt;I may have made mistakes&lt;/b&gt;

&lt;p&gt;I suppose this goes without saying, but there are a lot of knobs to be tweaked
here, and there could easily be something sub-optimal in my configuration,
makefiles, or what-have you. If you notice anything amiss, please say so and
I'll try to address it.&lt;/p&gt;

&lt;b&gt;This is just one machine&lt;/b&gt;

&lt;p&gt;As described above, I ran these tests on my MacBook Pro. The relative
performance of these tests might not be the same on different machines.&lt;/p&gt;

&lt;h2&gt;Update&lt;/h2&gt;

&lt;p&gt;Based on feedback from comments and elsewhere, I've updated a few of the numbers in the linked spreadsheet, along with the graphs.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;i&gt;Emscripten&lt;/i&gt;: I got an updated build with a better compiler, and the numbers are now much more in line with the other Javascript implementations.&lt;/li&gt;
  &lt;li&gt;&lt;i&gt;Java&lt;/i&gt;: I updated the JVM implementation to use a faster sin()/cos() implementation (there was a flag for this in the JBox2D code that I simply missed. It's no about 2.5x the speed of the native implementation. I also wasn't entirely clear about what I meant by the "JVM" -- so to be clear, this means the standard Mac OS X JDK 1.6 server JVM (there is no standard client JVM on the Mac).&lt;/li&gt;
&lt;/ul&gt;

None of this changes the core conclusions in any substantive way, however.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-2928355548056443624?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/2928355548056443624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=2928355548056443624' title='28 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/2928355548056443624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/2928355548056443624'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2011/12/for-those-unfamiliar-with-it-box2d-is.html' title='Box2D as a Measure of Runtime Performance'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>28</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-2082073579214507176</id><published>2010-09-16T12:33:00.001-04:00</published><updated>2010-09-16T13:40:08.377-04:00</updated><title type='text'>An Ugly Bug in the IE9 Beta</title><content type='html'>&lt;p&gt;Hot on the heels of my very happy discovery that IE9 finally &lt;a href="http://blog.j15r.com/2010/09/ie9-memory-leaks-finally-declared-dead.html"&gt;plugs its
leaks&lt;/a&gt;, I've found a subtle-but-important bug in the IE9 beta. Bear
with me, as it's a little tricky to explain.&lt;/p&gt;

&lt;h3&gt;The Good News&lt;/h3&gt;

&lt;p&gt;IE9 finally implements the standard HTML5 DOM element interfaces, which will
make many things simpler. Further good news: IE9 includes a nice debugger you
can use to explore these interfaces. &lt;a href="http://blogs.msdn.com/b/ie/archive/2010/09/02/dup-exploring-ie9-s-enhanced-dom-capabilities.aspx"&gt;As I understand it&lt;/a&gt;, the IE team
has cleaned up all the bizarre old COM bindings that have been giving
developers fits for years. So when you inspect an element in their nifty new
debugger, you get something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;document.body   {...}                     [Object, HTMLBodyElement]
- accessKey     ""                        String
- appendChild   function appendChild(...  Object, (Function)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;The Bad News&lt;/h3&gt;

&lt;p&gt;This is beautiful, and matches your expectations of the interfaces quite
nicely. But then I discovered this little gem:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;elem:           {...}                     DispHTMLImg
- [Events]
- [Expandos]
- [Methods]
- accessKey     ""                        String
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What on earth is this? It sure looks like an IDispatch interface to an element
-- but I thought we weren't supposed to be seeing that sort of thing anymore.
But if you resolve properties on the object using the Javascript VM, most of
them resolve the same way, so no harm done, right?&lt;/p&gt;

&lt;p&gt;Not so fast. When digging into a bug in my code, I kept running into this
bizarre situation where elements didn't seem to be comparing properly.
Specifically, I got into a situation where (ElemA == ElemB) &lt;em&gt;and&lt;/em&gt; (ElemB !=
ElemA). These were two different elements, so they shouldn't have been equal to
one another anyway, but the asymmetric equality relation was a really big
surprise!&lt;/p&gt;

&lt;p&gt;As you might have guessed, one of these two elements was an HTMLElement, while
the other was a DispHTMLDivElement. Ok, if one of them is a Disp interface to
an element and the other is a native DOM host object, you can imagine how the
comparison might get screwed up (I'm going on the assumption that IE didn't
expect to have those Disp objects exposed at all). Which begs the question of
how I got that reference in the first place.&lt;/p&gt;

&lt;p&gt;When I tried to reproduce the bug in isolation, everything seemed to work fine
-- no Disp references in sight. I finally tracked it down to the fact that
my code was running in an iframe, while the DOM elements themselves were in the
outer frame (this is a not-uncommon technique for isolating code). Specifically,
it seems to be triggered by the following situation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Outer page:
  &amp;lt;div id='target'&amp;gt;...&amp;lt;/div&amp;gt;

IFrame:
  &amp;lt;script&amp;gt;
  var target = parent.document.getElementById('target');
  target.onclick = function(evt) {
    // both 'evt' and 'elem' will be Disp interfaces
    var elem = evt.currentTarget;
  };
  &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So it appears that something's going wrong when marshalling the event object
from one frame to the other. And once you get one of these funky Disp objects,
all references you get from it will be Disp objects as well. Which opens you
to these comparison failures.&lt;/p&gt;

&lt;h3&gt;A couple of caveats&lt;/h3&gt;

&lt;p&gt;I'm assuming that the "Disp" part of these objects' names refers to IDispatch,
but if that's not correct it doesn't really change much. Also, you may have
noticed that I used the == comparison operator above -- it turns out that ===
behaves as expected. However, there's no good reason to use === when comparing
two objects.&lt;/p&gt;

&lt;h3&gt;A possible explanation&lt;/h3&gt;

&lt;p&gt;If I understand IE's architecture correctly, older versions appeared to use
DCOM for cross-frame communication. If I'm correct about this (and it's still
the case in IE9), then it may be that something just went wrong in the
marshalling of references from one frame to another (hence my assumption that
"Disp" means "IDispatch").&lt;/p&gt;

&lt;h3&gt;Does This Really Matter?&lt;/h3&gt;

&lt;p&gt;Yes. It might seem really subtle, but these are the kinds of bugs that can take
hours or days to track down when something goes wrong (and for which the fix is
non-obvious at best). And while putting your code in an iframe might seem like
a slightly odd thing to do, there are very good reasons for it under some
circumstances (I'll have more to say on precisely why this is important in a
follow-up post).&lt;/p&gt;

&lt;h3&gt;Repro&lt;/h3&gt;

&lt;p&gt;I've posted a relatively simple reproduction case &lt;a href="http://j15r.com/example/ie9_disp.html"&gt;here&lt;/a&gt;. It's a little
screwy, because it's a case hoisted out of a much more complex app, but it
should illustrate the issue reasonably well.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-2082073579214507176?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/2082073579214507176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=2082073579214507176' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/2082073579214507176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/2082073579214507176'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2010/09/ugly-bug-in-ie9-beta.html' title='An Ugly Bug in the IE9 Beta'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-7711488792731984589</id><published>2010-09-16T11:26:00.001-04:00</published><updated>2010-09-16T11:26:40.218-04:00</updated><title type='text'>IE9: Memory Leaks Finally Declared Dead</title><content type='html'>&lt;p&gt;It is with great pleasure that I can finally declare the &lt;a href="http://blog.j15r.com/2005/01/dhtml-leaks-like-sieve.html"&gt;infamous&lt;/a&gt;,
&lt;a href="http://blog.j15r.com/2005/05/drip-ie-leak-detector.html"&gt;painful&lt;/a&gt;, &lt;a href="http://blog.j15r.com/2005/06/another-word-or-two-on-memory-leaks.html"&gt;long-standing&lt;/a&gt;, &lt;a href="http://blog.j15r.com/2007/09/ies-memory-leak-fix-greatly-exaggerated.html"&gt;never&lt;/a&gt;
&lt;a href="http://blog.j15r.com/2009/07/memory-leaks-in-ie8.html"&gt;fixed&lt;/a&gt; IE memory leak bug fixed! With the release of IE9, I have
verified that every leak pattern I'm aware of is fixed. It's been a long-time
coming, but I'm starting to feel more confident that IE9 can be reasonably
called part of the "modern web" -- the web that is sufficiently powerful to
support complex applications, and not just lightly scripted documents.&lt;/p&gt;

&lt;p&gt;One caveat: Do be aware that your "standard" pages need to explicitly request
"IE9 Standards" mode, using either an HTTP response header or a meta tag like
the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;meta http-equiv='X-UA-Compatible' content='IE=9'/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Failure to do so, in addition to giving you all the old crufty bugs and quirks
in previous IE versions, will continue to leak memory, presumably because it is
using the DLLs from the old rendering engine.&lt;/p&gt;

&lt;p&gt;Now perhaps I can finally stop writing about this stupid bug!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-7711488792731984589?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/7711488792731984589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=7711488792731984589' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/7711488792731984589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/7711488792731984589'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2010/09/ie9-memory-leaks-finally-declared-dead.html' title='IE9: Memory Leaks Finally Declared Dead'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-3877713794049768334</id><published>2010-04-30T18:01:00.003-04:00</published><updated>2010-04-30T18:07:51.276-04:00</updated><title type='text'>Trying out the new Wave element</title><content type='html'>Google Wave just added a new "web element" that makes it easy to embed a wave in a blog or article, so I thought I'd try it out. If you're one of the two people who actually reads this, give it a shot. If you don't have a Wave account, you won't be able to edit -- if you need an invite, ping me at jgw@pobox.com.

&lt;div id="waveframe" style="width: 800px; height: 500px"&gt;&lt;/div&gt;
&lt;script type="text/javascript" 
  src="http://www.google.com/jsapi"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
google.load("wave", "1");
google.setOnLoadCallback(initialize);
function initialize() {
  var waveframe = document.getElementById("waveframe");
  var embedOptions = {
    target: waveframe,
    header: true,
    toolbar: true,
    footer: true
  };
  var wavePanel = new google.wave.WavePanel(embedOptions);
  wavePanel.loadWave("googlewave.com!w+ZK8FPqJvA");
}
&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-3877713794049768334?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/3877713794049768334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/3877713794049768334'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2010/04/trying-out-new-wave-element.html' title='Trying out the new Wave element'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-777892131432160304</id><published>2010-04-02T14:26:00.000-04:00</published><updated>2010-04-02T14:27:27.030-04:00</updated><title type='text'>Quake II in HTML5 -- What does this really mean?</title><content type='html'>&lt;p&gt;Now that we've finally been able to push our &lt;a href="http://code.google.com/p/quake2-gwt-port/"&gt;port&lt;/a&gt; of Quake II to the browser
public, it's time to discuss the questions "what's the point?" and "what does
this mean for the future?".&lt;/p&gt;

&lt;p&gt;Let me begin with a tweet I saw last night, which neatly summarizes a very
salient point:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Not sure if the best endorsement of JS engine speed in 2010 is ports of
  games from 1997...&lt;/p&gt;
  
  &lt;p&gt;http://twitter.com/tberman/status/11446377136&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well said. We should be setting the bar higher than this. The choice of Quake
II was mainly predicated on the fact that a Java port already existed, and this
was just a 20% project (more like -5%, actually -- nights and weekends for the
most part). I'm pretty certain Quake III would have ported just as easily
(perhaps more easily, as it was written specifically for hardware acceleration
and likely leans on the hardware a little more).&lt;/p&gt;

&lt;p&gt;So then there's the fact that it's running at frame rates about a third of what's
possible on the same hardware in C (or &lt;a href="http://bytonic.de/html/benchmarks.html"&gt;on the JVM&lt;/a&gt;, for that matter).
There are a few reasons for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are inefficiencies still to be worked out in WebGL implementations,
especially the expensive frame buffer read-back on Chrome.&lt;/li&gt;
&lt;li&gt;There are things being done in Javascript that really ought to be done in
vertex shaders; this especially applies to things like model animation
interpolation, which is a nasty hot spot in the Javascript code that could
easily be pushed to the shader.&lt;/li&gt;
&lt;li&gt;There are some things, such as dealing with packed binary data structures,
that are incredibly inefficient in Javascript (and I mean something like
100x slower than JVM or C code). This can be largely mitigated through
better APIs, such as the Khronos Group's &lt;a href="https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/doc/spec/TypedArray-spec.html"&gt;Typed Arrays&lt;/a&gt; spec.&lt;/li&gt;
&lt;li&gt;This code is fairly idiosyncratic, having been ported from straight C, and
exercises some code generation paths in the GWT compiler that could be
better optimized (using lots of small arrays, and lots of static methods,
still needs some work).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would be willing to hazard a guess that we could easily get another 30%
out of the frame rate with relatively minor tweaks. If the game were written
from the ground up to work with web technologies, it would likely be twice as
fast on any reasonable metric (frame rate, startup time, etc.). That's an
extremely rough estimate, but I'd be willing to bet on it.&lt;/p&gt;

&lt;p&gt;So back to our original question. What's the point? What this code currently
proves is that it's feasible to build a "real" game on WebGL, including complex
game logic, collision detection, and so forth. It also did an excellent job
exposing weak spots in the current specs and implementations, information we
can and will use to go improve them.&lt;/p&gt;

&lt;p&gt;Now if I were starting with a plain C code base, I would most likely prefer to
port it using a technology like &lt;a href="http://code.google.com/p/nativeclient/"&gt;NaCl&lt;/a&gt; -- that's what it's for. But while
it's not feasible to actually ship games on WebGL yet (it will be a while
before it's widely deployed enough for that), one can envision a world where
game developers can deploy their games as easily as we currently deploy web
pages, and users can play them just as easily. And that's a pretty damned
compelling world to imagine.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-777892131432160304?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/777892131432160304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=777892131432160304' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/777892131432160304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/777892131432160304'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2010/04/quake-ii-in-html5-what-does-this-really.html' title='Quake II in HTML5 -- What does this really mean?'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-1028765042795968269</id><published>2009-09-11T14:29:00.001-04:00</published><updated>2009-09-11T14:31:21.605-04:00</updated><title type='text'>Javascript Variables, Continued</title><content type='html'>&lt;p&gt;In my &lt;a href="http://blog.j15r.com/2009/08/where-should-i-define-javascript.html"&gt;previous post&lt;/a&gt;, I addressed the question of the speed of variable
access, as originally explored by Mike Wilcox &lt;a href="http://www.sitepen.com/blog/2009/08/10/web-page-global-variable-performance/"&gt;here&lt;/a&gt;. In the comment
section of his blog, he posted a cogent response to my concerns that I failed
to address at the time (about a month ago). Sorry about that, Mike -- I blame
the 10-month-old girl who consumes most of my time and attention lately :)&lt;/p&gt;

&lt;h1&gt;Terminology&lt;/h1&gt;

&lt;p&gt;A commenter on that post appears to take serious offense with my choice of
terminology, so let's start by clearing that up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Array Notation: What I am referring to here is the array-like syntax for
accessing properties on Javascript objects. I am fully aware that there is a
difference between accessing string-keyed and integer-keyed properties in this
way. But it is not uncommon to refer to this as array-access notation. Call it
what you will, but I suspect anyone reading this will have little trouble
understanding what I'm referring to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Globals and Fields: Perhaps I'm letting my Java-centric view of the world
poke through a bit here, but I thought it was fairly clear from the examples
I gave.  I was using the term "global" to refer to a globally-scoped variable
defined with an explicit "var" statement. The term "field" I used somewhat
loosely to refer to an explicitly-defined property on an object. Again, sorry
if this wasn't clear from context. Henceforth, I'll refer to the latter as
"properties", which is more accurate in a Javascript context.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now allow me a moment to clarify speicifically why I bring up the question of
"array access" notation vs. "dot" notation (call them what you will). The problem
with using them interchangeably in performance tests is that while logically
they both refer to properties on an object, we have no reason to believe that
their performance will be identical in all Javascript engines. In addition,
there is good reason to suspect that accessing globals via &lt;code&gt;window[name]&lt;/code&gt; may
be significantly different from simply accessing them via an unadorned &lt;code&gt;name&lt;/code&gt;
expression.&lt;/p&gt;

&lt;h1&gt;Mike's Concerns&lt;/h1&gt;

&lt;p&gt;From Mike's comment:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I think we were going for slightly different goals, and that makes your tests
  very complimentary to mine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is an entirely fair point. Let me attempt to justify the particular forms
of variable access that I chose to test. In a nutshell, I wanted to test the
precise form of usage that I see in much, if not all, idiomatic Javascript, and
that we produce from the GWT compiler. This involves global variables that are
declared explicitly, as in:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var g0 = 0, g1 = 'foo', ...;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And objects whose fields (or properties, if you prefer), are explicitly
declared and initialized (usually in a constructor function, but the expression
form below is common as well):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
  f0: 0,
  f1: 'foo',
  ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These correspond to static and instance variables, respectively, in Java source
code.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;One thing to note, and I’m pretty sure neither of us did, is that the JS
  engine may possibly resolve those variables in the code block before the code
  is executed. Keeping them in functions (and not in the global scope) should
  prevent that.&lt;/p&gt;
  
  &lt;p&gt;setLVars = function(){
    var a0=0;var a1=1;var a2=2;var a3=3;var a4=4; … 5000
  }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I believe this is referring to the above test of initializing local variables,
and it doesn't sound inplausible. In an attempt to work around this possibility,
the "locals" test I added separates variable declarations from their assignments,
and uses the same random values as all the other tests to initialize them.&lt;/p&gt;

&lt;h1&gt;A word on closures&lt;/h1&gt;

&lt;p&gt;When I added the test for variable access "via closure", it was to test a structure
I've seen used a lot to isolate the "global" namespaces used by separate chunks
of Javascript code. This pattern tends to look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(function() {
  var g0, g1, ...;

  function init() {
    // Do stuff with g0, g1, ...
  }

  init();
)();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a really useful pattern when you want to keep separately-loaded scripts
from stepping on each-others' toes, and I thought it worthwhile to see if using
such a structure imposed any significant overhead on access to globals.&lt;/p&gt;

&lt;p&gt;You may note that my results for closures are much more flattering on some
browsers than before. This is because I made a bad typo in the test and failed
to declare the variables properly. This led to them being declared implicitly
in the global scope.&lt;/p&gt;

&lt;h1&gt;Test Code&lt;/h1&gt;

&lt;p&gt;It also appears that both my dear commenter and Mike Wilcox himself had some
difficulty reproducing my results with the simple snippets I provided, so I am
publishing the test page &lt;a href="http://j15r.com/test/varSpeed.html"&gt;here&lt;/a&gt;. I've made a few changes in the process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I have changed references to "fields" to refer to "properties" for clarity.&lt;/li&gt;
&lt;li&gt;I added a test for "locals" that should be self-explanatory.&lt;/li&gt;
&lt;li&gt;I fixed a bug in the "closures" case that was skewing the results fairly badly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If anyone notices anything amiss with this code, please do let me know. I am
aware that the tests conflate read and write times, and that the accumulator
code makes their absolute values irrelevant. What I'm attempting to tease out
here is only the relative costs of defining variables in each scope.&lt;/p&gt;

&lt;h1&gt;Results&lt;/h1&gt;

&lt;p&gt;(Note that for simplicity's sake, I've simplified these results to only cover
Safari 4, IE8, Firefox 3.5, and Chrome 2)&lt;/p&gt;

&lt;p&gt;MacBook Pro 2.4 GHz Core 2 Duo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Safari 4:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals: 11ms&lt;/li&gt;
&lt;li&gt;Properties: 24ms&lt;/li&gt;
&lt;li&gt;Locals: 12ms&lt;/li&gt;
&lt;li&gt;Closures: 11ms&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firefox 3.5:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals: 44ms&lt;/li&gt;
&lt;li&gt;Properties: 47ms&lt;/li&gt;
&lt;li&gt;Locals: 14ms&lt;/li&gt;
&lt;li&gt;Closures: 91ms&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VMWare on aforementioned Mac:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;IE8:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals: 31ms&lt;/li&gt;
&lt;li&gt;Properties: 47ms&lt;/li&gt;
&lt;li&gt;Locals: 15ms&lt;/li&gt;
&lt;li&gt;Closures: 31ms&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chrome 2:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals: 28ms&lt;/li&gt;
&lt;li&gt;Properties: 30ms&lt;/li&gt;
&lt;li&gt;Locals: 5ms&lt;/li&gt;
&lt;li&gt;Closures: 6ms&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firefox 3.5:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals: 32ms&lt;/li&gt;
&lt;li&gt;Properties: 35ms&lt;/li&gt;
&lt;li&gt;Locals: 16ms&lt;/li&gt;
&lt;li&gt;Closures: 69ms&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, please note that the results for closures are rather different than in
my previous post, because of the aforementioned bug in my original test.&lt;/p&gt;

&lt;p&gt;Regardless, though, the most clear patterns that emerge here are as follows:
- In none of these cases are properties on a local object faster to access than
  globally-scoped variables.
- Locals are almost invariably faster than (or the same speed as) global or
  property accesses, which is not terribly surprising.
- Accessing variables via closure &lt;em&gt;can&lt;/em&gt; be as fast as accessing variables in
  the global scope, but on Chrome it's actually &lt;em&gt;faster&lt;/em&gt;, while on Firefox 3.5
  it's about twice as slow.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-1028765042795968269?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/1028765042795968269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=1028765042795968269' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/1028765042795968269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/1028765042795968269'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2009/09/javascript-variables-continued.html' title='Javascript Variables, Continued'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-5405455238489960784</id><published>2009-08-10T23:12:00.001-04:00</published><updated>2009-08-10T23:15:59.965-04:00</updated><title type='text'>Where should I define Javascript variables?</title><content type='html'>&lt;p&gt;I recently stumbled across this &lt;a href="http://www.sitepen.com/blog/2009/08/10/web-page-global-variable-performance/"&gt;article&lt;/a&gt; by Mike Wilcox at SitePen,
which suggests that defining Javascript variables in the global scope causes
reads and writes to them to be much slower than if they are defined as fields
on an object. While Javascript VMs never fail to surprise in their strange and
disparate behavior, something didn't quite smell right about this, so I decided
to dig in a bit further.&lt;/p&gt;

&lt;p&gt;As I understand it, the investigation was triggered by Mike noticing a large
number of global variables in the Google Docs graphics editor. The variables in
question are defined something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var rs=parseFloat;
var us="shape",vs="activeElement", ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In all likelihood, a combination of normal static variables, interned strings,
and such. In order to test the hypothesis that defining these variables in the
global scope could be a performance problem, he created a test that looks
something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Assume that v[i] is a randomly-created variable name.
obj = {};
setLocals = function(){
  for(var i=0;i&amp;lt;v.length;i++){
    obj[v[i]] = true;
  }
}

setGlobals = function(){
  for(var i=0;i&amp;lt;v.length;i++){
    window[v[i]] = true;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Tests for reads follow basically the same form. You can see the results in the
linked article, but the upshot is that accessing "globals" in this manner is
anywhere from 1x to 10x slower than the equivalent object field access.&lt;/p&gt;

&lt;p&gt;There are two main problems with this test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It always accesses globals via the window object explicitly.&lt;/li&gt;
&lt;li&gt;It doesn't explicitly declare the variables in either scope.
&lt;ul&gt;&lt;li&gt;This conflates creation with assignment.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's rewrite these tests to be closer to normal, idiomatic Javascript usage.
We will declare global variables explicitly, and reference them implicitly. We
will also explicitly declare the object fields explicitly, for as close an
apples-to-apples comparison as possible. Note that the random variables, as
well as the accumulator and return value, are probably-unnecessary attempts to
normalize for any static optimization tricks that newer Javascript VMs might be
playing.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Allocate a bunch of random values to be used later in assignments.
var r0 = Math.random(), r1 = Math.random(), ... ;

// Test assignment and reading of global variables.
var g0 = 0, g1 = 0, ... ;
function globals() {
  var a = 0;
  g0 = r0; g1 = r1; ... ;
  a += g0; a += g1; ... ;
  return a;
}

// Test assignment and reading of fields on a local object.
var obj = {f0 : 0, f1: 0, ... };
function locals() {
  var a = 0, o = obj;
  o.f0 = r0; o.f1 = r1; ... ;
  a += o.f0; a += o.f1; ... ;
  return a;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In addition, we'll test the the performance of the increasingly common pattern
of scoping variables via closure.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Test assignment and reading of locals via closure.
function closures() {
  var c0 = 0; c1 = 1; ... ;

  return function() {
    var a = 0;
    c0 = r0; c1 = r1; ... ;
    a += c0; a += c1; ... ;
    return a;
  };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is all far from "real-world" Javascript, but it's a lot closer than
referencing everything by name, using the array notation. I generated the above
code such that there were 1000 variables, assignments, and reads. I then
averaged the times over 100 runs, getting the following results:&lt;/p&gt;

&lt;p&gt;MacBook Pro 2.4 GHz Core 2 Duo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Safari 4:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals:  15ms &lt;/li&gt;
&lt;li&gt;Fields:   30ms &lt;/li&gt;
&lt;li&gt;Closures: 30ms &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firefox 3.0.12:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals:  60ms &lt;/li&gt;
&lt;li&gt;Fields:   43ms &lt;/li&gt;
&lt;li&gt;Closures: 78ms &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firefox 3.5.2:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals:  43ms &lt;/li&gt;
&lt;li&gt;Fields:   46ms &lt;/li&gt;
&lt;li&gt;Closures: 52ms &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;VMWare on aforementioned Mac:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;IE8:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals:  31ms &lt;/li&gt;
&lt;li&gt;Fields:   47ms &lt;/li&gt;
&lt;li&gt;Closures: 47ms &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chrome 2:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals:  31ms &lt;/li&gt;
&lt;li&gt;Fields:   47ms &lt;/li&gt;
&lt;li&gt;Closures: 47ms &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Firefox 3.0.8:&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;Globals:  35ms &lt;/li&gt;
&lt;li&gt;Fields:   29ms &lt;/li&gt;
&lt;li&gt;Closures: 68ms &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The absolute values aren't as important as the relative values for each
browser.  The most notable pattern is that globals and fields don't perform all
that differently from one-another, and referencing variables via closure is
almost invariably slower. This is a random smattering of browsers, and
doubtless others will perform differently. But most importantly, there's no
clear-cut advantage to either one.&lt;/p&gt;

&lt;p&gt;This has limited implications for hand-written code; you're almost always going
to want to write whatever makes the most sense to you, because the differences
aren't all that great either way. It &lt;em&gt;does&lt;/em&gt; have strong implications for tools
(like &lt;a href="http://code.google.com/webtoolkit"&gt;GWT&lt;/a&gt;) that &lt;em&gt;generate&lt;/em&gt; Javascript. Such tools have a high degree of
latitude in how they define variables, and these small effects can be amplified
for large programs.&lt;/p&gt;

&lt;p&gt;I'd say the moral of this story is that you must be careful to measure
precisely what you &lt;em&gt;think&lt;/em&gt; you're measuring, especially in as complex and
unpredictable a doman as Javascript VMs. I can understand how Mike arrived at
this point -- in any sane world, &lt;code&gt;(window[name])&lt;/code&gt; would be the same as
&lt;code&gt;(name)&lt;/code&gt;, since they do precisely the same thing. But we're not in a sane world
here, are we?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-5405455238489960784?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/5405455238489960784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=5405455238489960784' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5405455238489960784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5405455238489960784'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2009/08/where-should-i-define-javascript.html' title='Where should I define Javascript variables?'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-8760616729559292261</id><published>2009-07-12T23:28:00.003-04:00</published><updated>2009-10-28T09:33:42.234-04:00</updated><title type='text'>Memory Leaks in IE8</title><content type='html'>&lt;p&gt;Now that IE8's out, it seems I get to revisit this topic once again, which is
getting quite tedious. When Microsoft first began touting IE8 features, I
noticed a &lt;a href="http://msdn.microsoft.com/en-us/library/dd361842(VS.85).aspx"&gt;couple&lt;/a&gt; of &lt;a href="http://blogs.msdn.com/ie/archive/2008/08/26/ie8-performance.aspx"&gt;pages&lt;/a&gt; pointing out that they had done a great
deal of work to "mitigate" memory leaks in IE. The word "mitigate" sounds a bit
fishy, as the source of the problem is &lt;a href="http://blog.j15r.com/2005/01/dhtml-leaks-like-sieve.html"&gt;pretty fundamental&lt;/a&gt; to the
design of the COM interface that their script engine uses to access the DOM and
other native objects.&lt;/p&gt;

&lt;p&gt;As &lt;a href="http://blog.j15r.com/2007/09/ies-memory-leak-fix-greatly-exaggerated.html"&gt;you may recall&lt;/a&gt;, IE7 contained a rough attempt to solve this problem
by walking the DOM on unload, cleaning up leaks on any elements still there.
This helped somewhat, but left many common leak patterns unresolved (in
particular, any element removed from the DOM could still leak easily).&lt;/p&gt;

&lt;p&gt;From my tests, IE8 appears to have resolved all of the most common leak
patterns (as described in the two IE8 links above). In particular, I can't
uncover a single leak that doesn't at least get cleaned up on unload. This is
good news for IE users, because under most circumstances it means that the
browser won't get slow and bloated over time.&lt;/p&gt;

&lt;h3&gt;How IE8 leaks&lt;/h3&gt;

&lt;p&gt;With some cursory testing, however, I have uncovered at least one pattern that
still leaks memory on IE8. Consider the following code (which you can run
&lt;a href="http://j15r.com/example/spew.html"&gt;here&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// This approach hangs a massive js object from a dynamically created DOM
// element that is attached to the DOM, then removed. This pattern leaks
// memory on IE8 (in "IE8 Standards" mode).
function spew() {
  // Create a new div and hang it on the body.
  var elem = document.createElement('div');
  document.body.appendChild(elem);

  // Hang a *really* big-ass javascript object from it.
  var reallyBigAss = {};
  for (var i = 0; i &amp;lt; 5; ++i) {
    reallyBigAss[i] = createBigAssObject();
  }
  elem.__expando = reallyBigAss;

  // Complete the circular reference.
  // Comment out the following line, &amp;amp; the leaks disappear.
  elem.__expando.__elem = elem;

  // Remove it from the DOM. The element should become garbage as soon as
  // this function returns.
  elem.parentElement.removeChild(elem);

  // Just to give it a fighting chance to collect this garbage.
  CollectGarbage();
}

function createBigAssObject() {
  var o = {};
  for (var i = 0; i &amp;lt; 100000; ++i) {
    o[i] = 'blah';
  }
  return o;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will leak at runtime on IE8. It &lt;em&gt;does&lt;/em&gt; get cleaned up when the page
is unloaded, but it can still be a serious problem for long-running pages
(complex Ajax applications, for example).&lt;/p&gt;

&lt;p&gt;This particular example is admittedly somewhat contrived, but it is actually
isomorphic to a common use pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an element.&lt;/li&gt;
&lt;li&gt;Attach it to the DOM.&lt;/li&gt;
&lt;li&gt;Create some event handlers that result in circular refs.&lt;/li&gt;
&lt;li&gt;At some point in the future, after the user's done with it, remove it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sounds like a popup, a menu bar, or just about any interactive element that
gets created and removed in an application, n'est-ce pas?&lt;/p&gt;

&lt;h3&gt;What should I do about it?&lt;/h3&gt;

&lt;p&gt;Honestly, I would advise that you continue to do whatever you always have done.
Most Java[script] libraries (GWT, Dojo, jQuery, Prototype, etc.) already have
code in place to clean up these sorts of leaks, and they will continue to work
as advertised (I've personally checked GWT for leaks on IE8). It is unfortunate
that we have to continue doing these things, because they have a non-trivial
performance cost; and although it's taken a while, WebKit and Gecko seemed to
have finally nailed their own memory leak issues.&lt;/p&gt;

&lt;h3&gt;Aside: Drip is dead&lt;/h3&gt;

&lt;p&gt;I wrote &lt;a href="http://blog.j15r.com/2005/05/drip-ie-leak-detector.html"&gt;Drip&lt;/a&gt; some years back in order to help track down memory leaks
on Internet Explorer. I incorrectly assumed that it would be useful for a year
or two, as the problem would eventually be dealt with by Microsoft.&lt;/p&gt;

&lt;p&gt;Well, they did finally deal with the problem, primarily by building &lt;a href="http://blogs.msdn.com/gpde/pages/javascript-memory-leak-detector-v2.aspx"&gt;their own
memory leak detector&lt;/a&gt;. The good news is that it works quite well, and
is probably much more comprehensive than Drip ever was (and I haven't had much
time to maintain it). The first caveat I would add is that you almost
invariably want to change it to report "actual leaks" -- I don't find the IE6
and IE7 options to be useful in practice. The really bad news is that it
isn't useful on IE8 -- it will install, but doesn't catch any actual leaks, as
far as I can tell.&lt;/p&gt;

&lt;p&gt;Oct 28, 2009 update: Keilaron kindly points out that Microsoft's memory-leak detector article has been updated, and I've updated the above link accordingly. The linked article still claims that "In IE8 the problem is completely mitigated.", which appears to still be an overstatement at best.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-8760616729559292261?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/8760616729559292261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=8760616729559292261' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/8760616729559292261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/8760616729559292261'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2009/07/memory-leaks-in-ie8.html' title='Memory Leaks in IE8'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-3887182090323937982</id><published>2009-07-12T15:10:00.006-04:00</published><updated>2009-07-12T15:50:41.419-04:00</updated><title type='text'>GWT, JavaScript, and the Correct Level of Abstraction</title><content type='html'>&lt;p&gt;&lt;i&gt;[note: I originally posted this last December on the "&lt;/i&gt;&lt;a href="http://gwt-unofficial.blogspot.com/"&gt;&lt;i&gt;Unofficial GWT Blog&lt;/i&gt;&lt;/a&gt;&lt;i&gt;" that Scott Blum and I created, but neither one of us has had much time to maintain it, so I'm copying it back here to keep everything in one place.]&lt;/i&gt;

&lt;p&gt;John Resig seems to have stirred up a bit of a hornet's nest with a &lt;a href="http://ejohn.org/blog/javascript-language-abstractions/"&gt;recent
post&lt;/a&gt; on JavaScript language abstractions. I don't want to wade into
the details of the argument; I think Francisco over at cappuccino.org does a &lt;a href="http://cappuccino.org/discuss/2008/12/08/on-leaky-abstractions-and-objective-j/"&gt;great job&lt;/a&gt; of explaining the value of language abstractions that I
largely agree with.&lt;/p&gt;

&lt;p&gt;However, I've noticed a number of misunderstandings about GWT in this and other
articles, and I feel some clarification is in order.&lt;/p&gt;

&lt;h2&gt;Why Java?&lt;/h2&gt;

&lt;p&gt;First and foremost, let me clarify yet again the reasons behind the decision to
use Java as a source language. Allow me to quote from the &lt;a href="http://code.google.com/webtoolkit/makinggwtbetter.html"&gt;"Making GWT Better"&lt;/a&gt; document:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Why does GWT support the Java programming language instead of language X? In
  a word, tools. There are lots of good Java tools. That's the entire
  explanation. It isn't that we don't like language X or that we think the Java
  programming language is somehow superior. We just like the tools.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This point has perhaps been beaten to death, but there are a &lt;em&gt;lot&lt;/em&gt; of good
tools for Java, whether you love the language itself or not. Code completion,
automated refactoring, static error detection, code coverage, testing, and so
forth, are pretty hard to give up once you're used to them.&lt;/p&gt;

&lt;p&gt;But wait, there's more. Let's talk about compiler optimizations a bit. I'll
quote Ray Cromwell, from the comments on Resig's article:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;... Aggressive compiler optimizations, that happen before code is sent down
  the wire. This is a problem that no amount of trace-jitting will solve. Far
  from being bloated, as I demonstrated in my &lt;a href="http://timepedia.blogspot.com/2008/06/google-io-gwt-extreme-presentation.html"&gt;GWT Query
  presentation&lt;/a&gt; at Google I/O, GWT can produce code an order of
  magnitude smaller than most selector libraries in specific circumstances. GWT
  can prune dead code far better than any JS optimizer, and can obfuscate code
  to reduce size in a way that helps maximum GZIP/DEFLATE algorithms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What Ray's referring to here is the fact that a statically-typed language like
Java allows you to perform absolutely correct optimizations far in excess of
what is achievable without type information (There's a lot more to say on this
topic, which I'll save for a future post).&lt;/p&gt;

&lt;p&gt;Why is this so important for JavaScript output? In a word (or two), &lt;em&gt;code
size&lt;/em&gt;. Code that grows without bound is a serious problem for Javascript
applications, and static analysis gives us a &lt;em&gt;lot&lt;/em&gt; of leverage over the
problem. The GWT compiler can determine precisely which classes, methods,
and fields are actually used and aggressively prune everything else. And this
pruning feeds back into the iterative compilation process, allowing still
more optimizations (e.g., type-tightening, devirtualization, and so forth)
to be performed.&lt;/p&gt;

&lt;p&gt;Indeed, you can take this even further, with a concept we refer to as
runAsync(). With static whole-program analysis, it is possible to automatically
break a program into optimal fragments at user-defined cut points. This is
still experimental, but the preliminary results &lt;a href="http://groups.google.com/group/Google-Web-Toolkit-Contributors/browse_thread/thread/eb9c8cf046cbaaf2"&gt;look pretty good&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To put all this in concrete terms, check out this &lt;a href="http://timepedia.blogspot.com/2008/06/design-patterns-vs-gwt-compiler.html"&gt;great example&lt;/a&gt; on Ray's blog showing the following transformation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  public class MyArray implements Iterable&amp;lt;string&amp;gt; {  
    private String[] items = {"foo", "bar", "baz"};  

    public Iterator&amp;lt;string&amp;gt; iterator() {  
      return new StringArrayIterator(items);  
    }  

    private class StringArrayIterator implements Iterator&amp;lt;string&amp;gt; {  
      private String[] items;  
      private int index;  

      public StringArrayIterator(String[] items) {  
        this.items = items;  
        this.index = 0;  
      }  

      public boolean hasNext() {  
        return index &amp;lt; items.length;  
      }  

      public String next() {  
        return items[index++];  
      }  

      public void remove() {  
        throw new UnsupportedOperationException();  
      }  
    }  
  }  

  void iterate() {
    MyArray m = new MyArray();  
    for(String s : m)   
      Window.alert(s);  
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;iterate()&lt;/code&gt; becomes&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  function $iterate(m){  
    var s, s$iterator;  
    for (s$iterator = $MyArray$StringArrayIterator(new MyArray$StringArrayIterator(), m.items);  
       s$iterator.index &amp;lt; s$iterator.items.length;) {  
      s = s$iterator.items[s$iterator.index++];  
      $wnd.alert(s);  
    }  
  }  
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which becomes something like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  function x(a){var b,c;for(c=y(new z(),a.a);c.b&amp;lt;c.a.length;){b=c.a[c.b++];$wnd.alert(b);}}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The point of going into all this detail about tools and optimization is that
choosing Java as a source language gives GWT leverage that would have been
provably impossible in JavaScript. It's most emphatically &lt;em&gt;not&lt;/em&gt; about loving or
hating any given language, or providing Java programmers with a way to &lt;em&gt;avoid&lt;/em&gt;
JavaScript -- it's a pragmatic decision based upon specific, measurable
benefits.&lt;/p&gt;

&lt;p&gt;I've seen lots of assertions that various languages are either "higher level"
or "lower level" than others, without any clear definition of what metric is
being used to justify these statements. For example, "JavaScript is the
assembly language of the web" or "Java is a low-level language because it
doesn't have closures and dynamic typing". These sorts of arguments are
pointless at best, and at times simply disingenuous. What matters is not some
ill-defined notion of a language's "level of abstraction", but rather what you
can actually achieve with it.&lt;/p&gt;

&lt;h2&gt;JavaScript Interop&lt;/h2&gt;

&lt;p&gt;So what if I &lt;em&gt;need&lt;/em&gt; to write or use existing Javascript code? Most everyone
seems to finally be aware that it's possible to write JavaScript directly in
your Java source using &lt;a href="http://googlewebtoolkit.blogspot.com/2008/07/getting-to-really-know-gwt-part-1-jsni.html"&gt;JavaScript Native Interface&lt;/a&gt; methods, like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  // Java method declaration...
  native String flipName(String name) /*-{
    // ...implemented with JavaScript
    var re = /(\w+)\s(\w+)/;
    return name.replace(re, '$2, $1');
  }-*/;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What doesn't seem to be clear is just how fundamental a feature this is. I've
seen various people suggest that this is somehow "circumventing" the "normal"
way of doing things -- and while it's true that you lose some of the benefits
of Java type-checking, optimization, and debugging in these methods, they're
also the foundation upon which all the GWT libraries are built. And there's no
particular reason they have to be short snippets, either. They can be complex
methods and classes that reach back into Java code, pass exceptions around,
and so forth.&lt;/p&gt;

&lt;p&gt;What about calling into existing JavaScript libraries, or exposing GWT classes
to JavaScript code? For the former, check out Sanjay Jivan's &lt;a href="http://code.google.com/p/smartgwt/"&gt;SmartGWT&lt;/a&gt; library, which wraps the massive &lt;a href="http://www.smartclient.com/"&gt;Isomorphic SmartClient&lt;/a&gt; library. For the latter, have a look at Ray Cromwell's
GWT-Exporter &lt;a href="http://code.google.com/p/gwt-exporter/"&gt;gwtexporter&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;It's also worth noting that this functionality, combined with &lt;a href="http://googlewebtoolkit.blogspot.com/2008/08/getting-to-really-know-gwt-part-2.html"&gt;Overlay Types&lt;/a&gt; makes it really easy to efficiently parse and operate on JSON
structures. Once again, you get a side-benefit: once you've written the overlay
type for a particular JSON type, everyone using it gets code completion and
documentation for free. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  var customerJsonData = [
    { "FirstName" : "Jimmy", "LastName" : "Webber" },
    { "FirstName" : "Alan",  "LastName" : "Dayal" },
    { "FirstName" : "Keanu", "LastName" : "Spoon" },
    { "FirstName" : "Emily", "LastName" : "Rudnick" }
  ];

  class Customer extends JavaScriptObject {
    protected Customer() { } 

    public final native String getFirstName() /*-{ return this.FirstName; }-*/;
    public final native String getLastName()  /*-{ return this.LastName;  }-*/;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which means, as a user of this class, if I get a Customer type from somewhere,
I don't have to ask what fields and methods are available. The IDE can simply
tell me.&lt;/p&gt;

&lt;h2&gt;HTML DOM Integration&lt;/h2&gt;

&lt;p&gt;But don't GWT's abstractions keep you from just working with DOM elements?
Again, no. It has always been possible to work with the DOM from GWT (how else
do you think all those widgets get implemented?), but as of 1.5, it's gotten a
lot easier. See this &lt;a href="http://sites.google.com/site/io/surprisingly-rockin-javascript-and-dom-programming-in-gwt"&gt;Google IO presentation&lt;/a&gt; for details. Here's a
taste, though:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  TableElement table = ...;
  String s = table.getRows().getItem(0).getCells().getItem(0).getInnerText();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which of course translates to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  var s = table.rows[0].cells[0].innerText;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the important addition that as you type "table.[ctrl-space]", the IDE can
actually tell you that "getRows()" is an option. Given that TextAreaElement
alone has nearly 100 methods, that starts to be pretty useful.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ejohn.org/blog/javascript-language-abstractions/"&gt;The statement&lt;/a&gt; "You are likely to never see a DOM object or pieces of
the native JavaScript language" is actually only as true as you want it to be.
Most JavaScript frameworks provide some sort of higher-level abstraction than
simple DOM elements, and GWT is no exception, but you should pick the &lt;em&gt;right&lt;/em&gt;
level of abstraction for the task at hand.&lt;/p&gt;

&lt;h2&gt;Independently Useful Parts&lt;/h2&gt;

&lt;p&gt;Finally, we have the question of whether (GWT === GWT's libraries). This is
another common misconception -- GWT looks interesting, but I don't like the
way their widget library works. That's like saying you like JavaScript, but
not the way Prototype (or whatever) works.&lt;/p&gt;

&lt;p&gt;GWT "eats its own dogfood" almost all the way down. That is to say, there's
practically no module you can't replace (including the JRE). Like the DOM and
JRE modules, but not all the widgetry? Write your own widgets. Don't like any
of the modules? Replace the whole bloody thing! The many problems of building
browser-based UIs are not yet well-solved in the state of the art, so it's
highly unlikely that GWT's widget library represents a "perfect" solution. For
a completely different take on how a widget library should work, have a look at
the &lt;a href="http://extjs.com/products/gxt/"&gt;Ext-GWT&lt;/a&gt; library.&lt;/p&gt;

&lt;h2&gt;To Sum Up&lt;/h2&gt;

&lt;p&gt;I hope I've managed to convey the pragmatic goals that underlie GWT's design
decisions, and the methods we've used to achieve them. There are still a
million things we'd like to build and/or change, but I feel like it's off to a
pretty good start. Nothing would make me happier than if we could stop arguing
about abstract notions of what language is "right" and focus on practical goals
and metrics.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-3887182090323937982?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/3887182090323937982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=3887182090323937982' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/3887182090323937982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/3887182090323937982'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2009/07/note-i-originally-posted-this-last.html' title='GWT, JavaScript, and the Correct Level of Abstraction'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-5195513371883936862</id><published>2007-09-17T16:08:00.002-04:00</published><updated>2009-07-12T21:34:26.138-04:00</updated><title type='text'>IE's Memory Leak Fix Greatly Exaggerated</title><content type='html'>&lt;p&gt;So Microsoft (as reported &lt;a href="http://ajaxian.com/archives/ie-memory-leaks-be-gone"&gt;here&lt;/a&gt; and
&lt;a href="http://novemberborn.net/javascript/memory-leaks-gone"&gt;here&lt;/a&gt;) recently released a "cumulative security update" for
IE that fixes its egregious memory leaks.  Sounds great.  Even if it takes a
while to get everybody updated, at least the problem is fixed and we can all
stop bending over backwards to work around this problem in our libraries,
right.&lt;/p&gt;

&lt;h2&gt;Not So Fast&lt;/h2&gt;

&lt;p&gt;Let's have a look at the &lt;a href="http://support.microsoft.com/kb/929874/"&gt;actual knowledge-base article&lt;/a&gt; to see exactly
what it says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;"... a Web page that uses JScript scripting code, a memory leak occurs in
  Internet Explorer. When you visit a different Web page, the leaked memory is
  not released."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So far so good. It even references the original &lt;a href="http://support.microsoft.com/kb/830555/"&gt;"circular-reference"
knowledge-base article&lt;/a&gt;, implying that this is indeed what is fixed.&lt;/p&gt;

&lt;p&gt;When I saw this article, I nearly spilled tea all over the keyboard. They
really fixed this issue? You mean I can untangle all the painful code in GWT
that works around this issue, diligently cleaning up all its circular DOM
references under all sorts of circumstances?&lt;/p&gt;

&lt;h2&gt;Settle Down, Beavis&lt;/h2&gt;

&lt;p&gt;Before I got too excited, I had to do a little gut-check. Did they really go
back and make it possible for their garbage collector to chase references
through COM objects?  That would be wonderful, but I'm not holding my breath.&lt;/p&gt;

&lt;p&gt;And it's a good thing, because there's basically no way in hell they did that.
In fact, it turns out that all they did was write a little code to sweep the
DOM on unload and clean up all the extant circular references on those
elements. This means that &lt;em&gt;all elements not still attached on unload are still
leaked, along with the transitive closure over all references Javascript
objects&lt;/em&gt;. In even marginally complex applications, that means you're still
going to leak like a bloody sieve!&lt;/p&gt;

&lt;p&gt;I put together a &lt;a href="http://j15r.com/example/spew.html"&gt;little test script&lt;/a&gt; to show this in action. Have a look
in any version of IE, and watch its spew memory!&lt;/p&gt;

&lt;h2&gt;I'm With Alex ...&lt;/h2&gt;

&lt;p&gt;... &lt;a href="http://alex.dojotoolkit.org/?p=620"&gt;on this one&lt;/a&gt;. This is more like a bad joke than anything else. I
recognize that fixing IE's memory leaks is a really complex problem, but the
fact that it's not being done is still more evidence that Microsoft is
abandoning IE, at least as far as any real progress is concerned. I just wish
they would come out and say it.&lt;/p&gt;

&lt;h2&gt;In the Meantime&lt;/h2&gt;

&lt;p&gt;Don't go ripping out that memory-leak cleanup code. And keep checking for leaks (perhaps with
&lt;a href="http://code.google.com/p/iedrip/"&gt;Drip&lt;/a&gt;).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-5195513371883936862?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/5195513371883936862/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=5195513371883936862' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5195513371883936862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5195513371883936862'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2007/09/ies-memory-leak-fix-greatly-exaggerated.html' title='IE&apos;s Memory Leak Fix Greatly Exaggerated'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820974095264849</id><published>2007-01-07T17:04:00.001-05:00</published><updated>2009-07-12T15:47:15.682-04:00</updated><title type='text'>This Old Blog</title><content type='html'>&lt;p&gt;I think I may have broken the 'longest period of time between two blog posts' record, at roughly two years. The few people who remember it will probably be asking themselves, 'what the hell happened to it, anyway?'&lt;/p&gt;

&lt;p&gt;Well, you may not be terribly surprised to learn that I took a job at Google, and have been incredibly busy in the intervening time, working on the Google Web Toolkit. Initially, I tried to keep up with the blog and related flood of random email, but it got to be a bit more than I had time to deal with, so I just decided to nuke it so I could concentrate. This worked, of course, but seemed to irritate a few people who saw a little value in some of the posts.&lt;/p&gt;

&lt;p&gt;Now that I've got a little more time, I've decided to resurrect it. I kept copies of the old articles around, some of which I've re-posted. I apologize for the loss of the old comments -- some of them were really helpful, but they're really a pain to get back into Blogger (maybe I'll find a way to do this easily sometime).&lt;/p&gt;

&lt;p&gt;I do plan on covering largely the same subjects, and please feel free to email me with questions or subjects you'd like me to cover.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820974095264849?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820974095264849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820974095264849' title='61 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820974095264849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820974095264849'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2007/01/this-old-blog.html' title='This Old Blog'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>61</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820501329458782</id><published>2005-07-11T16:22:00.000-04:00</published><updated>2007-01-07T16:23:33.303-05:00</updated><title type='text'>Google Maps Information</title><content type='html'>I've been getting a slow but steady stream of requests for more information on how to work with Google Maps. I would love to respond to each of these individually, but honestly haven't been doing much with it since I wrote my first few articles on the subject.

Fortunately, I just ran across the &lt;a href="http://googlemapsmania.blogspot.com/"&gt;Google Maps Mania&lt;/a&gt; blog. It seems to be doing a pretty good job of aggregating all of the stuff going on with Maps at the moment. I'm really quite amazed at the array of different things people are building with it (and I doubt there's any way I could keep up with it all anyway).

Happy mapping to all!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820501329458782?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820501329458782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820501329458782' title='52 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820501329458782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820501329458782'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/07/google-maps-information.html' title='Google Maps Information'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>52</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820678690085032</id><published>2005-06-22T16:50:00.001-04:00</published><updated>2009-07-12T16:07:42.979-04:00</updated><title type='text'>Another Word or Two on Memory Leaks</title><content type='html'>&lt;p&gt;Ok, I promised to explain in more detail how to get rid of memory leaks once
you've found them. Though I haven't had time to gather all of the information
and examples I would have liked, I have run across a few external resources
that might be of help.&lt;/p&gt;

&lt;p&gt;The first of these is a new &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ie_leak_patterns.asp"&gt;Microsoft Technical Article&lt;/a&gt; that discusses
the various forms that IE memory leaks can take in some detail. Particularly
interesting is the fact that it discusses an even more obscure type of leak
that's not even a DOM element. It's definitely worth a read.&lt;/p&gt;

&lt;p&gt;A bit more information on JavaScript closures can be found on Eric Lippert's
blog (which I highly recommend) &lt;a href="http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a nice, straightforward library that does an excellent job helping you
avoid the problem altogether, take a look at Mark Wubben's &lt;a href="http://novemberborn.net/javascript/event-cache"&gt;Event
Cache&lt;/a&gt;.  I particularly like the fact that if you follow a simple
set of rules, then you cannot easily leak elements.&lt;/p&gt;

&lt;h2&gt;On Another Note&lt;/h2&gt;

&lt;p&gt;I suggested earlier that the slowdown associated with leaking large amounts of
memory in IE might be associated with hash tables or something similar getting
full and therefore more inefficient. Eric Lippert left the following comment,
which makes perfect sense to me and seems more likely to characterize the
problem:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The symbol tables are very search-efficient. What's more
  likely is that the non-generational mark and sweep garbage collector is getting
  more and more full, and therefore taking longer and longer to walk each time a
  collection happens. A generational GC, like the .NET framework's GC, solves
  this problem by not GCing long-lived networks of objects very often.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And don't worry, I haven't forgotten about Drip at all. As time allows, I will
be adding the features that I mentioned earlier. Of course, if anyone else
wants to play with the &lt;a href="http://sourceforge.net/projects/ieleak/"&gt;source&lt;/a&gt; and make their own additions, please
feel free!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820678690085032?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820678690085032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820678690085032' title='62 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820678690085032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820678690085032'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/06/another-word-or-two-on-memory-leaks.html' title='Another Word or Two on Memory Leaks'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>62</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-5713652619662723937</id><published>2005-06-06T18:15:00.000-04:00</published><updated>2007-01-08T18:20:23.726-05:00</updated><title type='text'>Drip 0.2</title><content type='html'>Happy Monday morning to everyone (or, depending upon where you may be, evening).  This is just a quick note to announce &lt;a href="http://www.outofhanwell.com/ieleak/Drip-0.5.exe"&gt;Drip 0.2&lt;/a&gt;!  Here is a quick list of changes in this version:
&lt;ul&gt;
&lt;li&gt;The main window is now resizeable.&lt;/li&gt;
&lt;li&gt;The property list is sorted.&lt;/li&gt;
&lt;li&gt;Property lists are now separate from the leak dialog. You can double-click on an element to see its properties. And you can double-click on any object property to see &lt;span style="font-style: italic;"&gt;its&lt;/span&gt; properties.  Think of it as a poor-man's expandable property list.&lt;/li&gt;
&lt;li&gt;The source is also available &lt;a href="http://sourceforge.net/projects/ieleak/"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
My current list of definitely known issues is as follows:
&lt;ul&gt;
&lt;li&gt;Still need to hook node.cloneNode() to catch all possible leaks.&lt;/li&gt;
&lt;li&gt;Still need to hook new windows as they are created.&lt;/li&gt;
&lt;li&gt;It sometimes reports that leaks are coming from about:blank rather than their actual source.&lt;/li&gt;
&lt;/ul&gt;
And my current list of &lt;span style="font-style: italic;"&gt;possible&lt;/span&gt; issues is:
&lt;ul&gt;
&lt;li&gt;A couple of people have mentioned crashes occuring, which I have not yet been able to reproduce. If anyone having such a problem has a chance to build the source and catch this in a debugger, that would be wonderful.&lt;/li&gt;
&lt;li&gt;I've also heard mention of issues with deeply-nested frames.  My demo leak &lt;a href="http://sorry.i/lost/this"&gt;test page&lt;/a&gt; should exhibit this issue, but seems to work fine.  Again, any help appreciated.&lt;/li&gt;
&lt;/ul&gt;
As always, please let me know of any other issues you discover, suggestions, and (even better) patches. And I haven't forgotten about my promise to provide a solid overview of how to deal with leak issues.  I'm still doing a bit of research on the subject, but this will be forthcoming soon!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-5713652619662723937?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/5713652619662723937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=5713652619662723937' title='104 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5713652619662723937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5713652619662723937'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/06/drip-02.html' title='Drip 0.2'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>104</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-5457472173331097704</id><published>2005-06-04T18:20:00.001-04:00</published><updated>2009-07-12T16:15:32.404-04:00</updated><title type='text'>Drip Redux</title><content type='html'>&lt;p&gt;Wow.  Thanks for all the excellent feedback on Drip. It was really just a tool
that I needed for myself, but I'm glad that it may prove useful for others as
well.&lt;/p&gt;

&lt;p&gt;There were a lot of comments, both here and on Slashdot, so I'm going to try to
put as many of my thoughts and responses as possible in this post. As such, it
may be a bit of a grab-bag.&lt;/p&gt;

&lt;h2&gt;Exacerbating the problem&lt;/h2&gt;

&lt;p&gt;The first point I want to make is in response to one or two comments here, and
many on Slashdot: That is, that I am not particularly concerned about whether
or not I am exacerbating the problem by helping developers to "work around"
IE's issues.  Don't get me wrong; I find it just as unfortunate as everyone
else that these problems exist in the first place. It is truly awful that
developers using such a high-level tool as a web browser have to take memory
allocation issues into account. Particularly given the fact that they're not
really given the tools to effectively deal with them (window.CollectGarbage()
doesn't count, since it won't really fix the problem).&lt;/p&gt;

&lt;p&gt;Anyone who's spent a significant amount of time developing software has to
realize that they will &lt;em&gt;always&lt;/em&gt; be dealing with inadequacies of their tools and
platforms. This has always been the case. It doesn't mean that vendors
shouldn't fix their mistakes, but it &lt;em&gt;does&lt;/em&gt; mean that you can't usually bitch
at your customers for their choice of platform. If you are going to make
software development your profession, then you must generally accept this
responsibility.  Certainly there are cases where you can dictate the details of
the client's platform, but this is not the case for most vendors.&lt;/p&gt;

&lt;p&gt;I also want to point out two things about this specific problem. First, IE's
memory leak issues stem largely from the underlying model that allows scripting
languages to interface with native COM objects (that is, making all objects
accessible to scripting languages COM objects deriving from IDispatch). While
imperfect, this model is also quite efficient -- and given that it was
developed in the mid-90's, not an unreasonable compromise at the time. The
second point I want to make is that IE is &lt;em&gt;not&lt;/em&gt; the only browser with this
problem. Mozilla had fairly severe memory leak issues until recently, and I've
been told that Safari does as well. So let's not use this as an excuse to jump
all over Microsoft.&lt;/p&gt;

&lt;h2&gt;When do leaks matter?&lt;/h2&gt;

&lt;p&gt;This is another point that I think bears some discussion. If you've spent a
little time pointing Drip at existing sites, you've probably found that most
sites exhibit no issues at all. This is simply because most sites simply don't
use enough complex DHTML (with complex object graphs and the like) to create
the specific sort of circular references that cause leaks. Most sites that &lt;em&gt;do&lt;/em&gt;
have a few leaks seem to be of PARAM objects passed to Java and/or Flash
components. I've gotten mixed reports on when this happens, and when it causes
a significant leak, so the jury's still out on whether this matters.&lt;/p&gt;

&lt;p&gt;On the other hand, I saw one comment to the effect that Google Maps leaks a
&lt;em&gt;lot&lt;/em&gt; of elements. This is exactly the sort of application that is in danger of
leaking enough to matter. If you look at the Maps code, you'll discover that
they've done an excellent job of abstracting the components that comprise the
application, and it's quite easy to follow (if you de-obfuscate it, anyway).
And I believe that the fact that it leaks so much is actually an indication
that its developers have done a &lt;em&gt;good&lt;/em&gt; job.  The problem is that the very
abstractions that make a code base of that size manageable make it &lt;em&gt;really&lt;/em&gt;
easy to create leaks. Because there are a lot of references among all of its
objects, and most DOM elements are wrapped in one way or another, even a single
leak can cause the entire reference graph to leak. Nasty, huh?&lt;/p&gt;

&lt;h2&gt;How do I fix leaks?&lt;/h2&gt;

&lt;p&gt;This is a pretty complex question. So I've decided to punt this to a
forthcoming post. There are a lot of resources out there on this subject, but I
hope to gather as much of it as possible into one post so that I can provide a
reasonable framework for finding and dealing with them.&lt;/p&gt;

&lt;h2&gt;What now?&lt;/h2&gt;

&lt;p&gt;I've gotten a lot of helpful suggestions and a couple of bug reports. What I
would like to do now is to list all of the fixes and enhancements that I can
think of, and solicit advice on how to prioritize them. Once I've had another
pass at the code, I will release the source as well so that you can all help
maintain it! This is my current list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deal with deeply nested frames. This is a real issue for a lot of sites -- apparently Drip only hooks one level of nested frames, but fails to hook deeper windows.&lt;/li&gt;
&lt;li&gt;Hook the cloneNode() method.  This is simply an oversight on my part, but it's necessary to catch all possible leaks.&lt;/li&gt;
&lt;li&gt;Resizable window. This was just me being lazy. I've gotten really used to constraint-based layout in the Java world, and to be honest, I just didn't want to deal with doing this by hand in MFC.&lt;/li&gt;
&lt;li&gt;Sorted and expandable element properties.  'Nuff said.&lt;/li&gt;
&lt;li&gt;Hook new windows (via window.open).  I think this is feasible, and will do my best.&lt;/li&gt;
&lt;li&gt;Anything else you guys can think of!&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-5457472173331097704?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/5457472173331097704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=5457472173331097704' title='51 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5457472173331097704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/5457472173331097704'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/06/drip-redux.html' title='Drip Redux'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>51</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-9039705590634461228</id><published>2005-05-31T18:02:00.001-04:00</published><updated>2009-07-12T16:26:13.077-04:00</updated><title type='text'>Drip: IE Leak Detector</title><content type='html'>&lt;p&gt;To anyone still following this site, my apologies for taking a millenium or two
between posts recently. Things have been a bit crazy of late, but I have
something to introduce that will hopefully make up for the radio silence:&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://code.google.com/p/iedrip/"&gt;Drip&lt;/a&gt; -- an Internet Explorer leak detector&lt;/h2&gt;

&lt;p&gt;Over the last few months, a number of people have written to me or left
comments asking questions about their memory leak issues with DHTML (or AJAX or
whatever-you-want-to-call-it-this-week) applications.  Unfortunately, there's
not much I could offer in the way of advice that most people don't already
know. Get rid of closures, unhook your event handlers, etc. This advice just
isn't all that helpful when you've got a giant mess of JavaScript (often
inherited) and visually detecting leak scenarios can be maddeningly subtle.&lt;/p&gt;

&lt;p&gt;I did, however, find it quite surprising that no one had ever built a leak
detector for Internet Explorer (or apparently for any other browser with leak
problems; Mozilla has some, but they seem to be more for developers working on
Mozilla itself, and the browser does a pretty good job of cleaning up leaks
anyway). So I built one.&lt;/p&gt;

&lt;h2&gt;What it Does&lt;/h2&gt;

&lt;p&gt;It's a pretty simple application. Basically, it lets you open an HTML page (or
pages, in succession) in a dialog box, mess around with it, then check for any
elements that were leaked.&lt;/p&gt;

&lt;p&gt;The interface is currently rather spartan.  Here's what the main app looks
like:&lt;/p&gt;

&lt;p&gt;[Sorry, I lost the image somewhere along the way]&lt;/p&gt;

&lt;p&gt;On the top you'll notice what looks like a crude version of Explorer's
navigation bar. You've got the standard back and forward buttons, the URL box,
and the 'go' button. These behave exactly as you might expect.  To the right of
it, however, is a 'check leaks' button, which will be grayed out when you first
run the app. In order to try it out, you will first need to go to an HTML page
(preferably one that you suspect leaks). The test page at [sorry I lost this
page] will work.  When you load this page, the 'check leaks' button will become
enabled.  Click it to see the following report:&lt;/p&gt;

&lt;p&gt;[Yet again, I lost the image somewhere along the way]&lt;/p&gt;

&lt;p&gt;This simple page leaks two DOM elements, a DIV and a BUTTON. These two elements
are displayed in the top list, along with their source documents (useful if
you've loaded more than one document between leak tests, or if you have more
than one frame), the number of outstanding references on them, and their ID and
CLASS attributes.&lt;/p&gt;

&lt;p&gt;If you click on one, you'll see a list of its enumerable attributes in the
bottom list. A particularly useful attribute for identifying the elements is
'innerHTML'.&lt;/p&gt;

&lt;h2&gt;Blowing Memory&lt;/h2&gt;

&lt;p&gt;Back to the main dialog for a moment. You might also have noticed the
interestingly-titled 'blow memory' button. Its function is simple: to
constantly reload a page as fast as it can, and to report the process' memory
usage in the list box below. This is a helluva lot easier than pressing F5 for
hours to determine how fast a page leaks memory.&lt;/p&gt;

&lt;h2&gt;How it Works&lt;/h2&gt;

&lt;p&gt;Fortunately, Internet Explorer's architecture made this app fairly easy to
build.  It's basically a simple MFC app with a browser COM component in it. The
strategy for catching leaked elements is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When a document has been downloaded, sneakily override the document.createElement() function so that the application is notified of all dynamically-created elements.&lt;/li&gt;
&lt;li&gt;When the document is fully loaded, snag a reference to all static HTML elements.&lt;/li&gt;
&lt;li&gt;To detect leaks:  navigate to a blank HTML page (so that IE attempts to release all of the document's elements),&lt;/li&gt;
&lt;li&gt;force a garbage-collection pass (by calling window.CollectGarbage()),&lt;/li&gt;
&lt;li&gt;and look at each element to see if it has any outstanding references (by calling AddRef() and Release() in succession on it).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within the leak dialog, each element's attributes are discovered and enumerated using the appropriate IDispatch/ITypeInfo methods.&lt;/p&gt;

&lt;h2&gt;Caveats&lt;/h2&gt;

&lt;p&gt;This is basically an alpha release. The interface more or less blows, and I may
have left glaring holes in the leak-detection strategy or in the code itself.
It seems to work for me, but I would really like for anyone using it to keep an
eye out for any problems so that I can fix them. And please don't hesitate to
contact me, of course, if you have any ideas, praise, criticism, or even rants
to offer. I really want this to help people to stop dealing with these
god-awful leaks, and since Microsoft doesn't seem inclined to fix this design
flaw, we can at least try to make it more bearable.&lt;/p&gt;

&lt;h2&gt;What Next?&lt;/h2&gt;

&lt;p&gt;Obviously, I would like any feedback I can get. There are definitely some
interface quirks I need to iron out. And I would like to do more to help
determine the actual &lt;em&gt;cause&lt;/em&gt; of each leak.  There are a few things that I would
like to find out, and if anyone has any pointers, please share them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can you perform similar tricks with Safari/KHTML or Opera? (I know you can with Mozilla, but since it doesn't really leak much, that seems rather pointless)&lt;/li&gt;
&lt;li&gt;Does anyone know if it's possible to enumerate variables on one of IE's JavaScript closures? (meaning the stack frame hanging off of the function reference)&lt;/li&gt;
&lt;li&gt;How about enumerating expandos on IE DOM objects from C++? (I only seem to get built-in properties from ITypeInfo)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm sure other questions will come up in the near future.  Oh, and I &lt;em&gt;will&lt;/em&gt; be
releasing the source before too long, as soon as I get a few things cleaned up.&lt;/p&gt;

&lt;p&gt;Happy leak hunting!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-9039705590634461228?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/9039705590634461228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=9039705590634461228' title='126 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/9039705590634461228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/9039705590634461228'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/05/drip-ie-leak-detector.html' title='Drip: IE Leak Detector'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>126</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820191874008652</id><published>2005-04-07T09:38:00.001-04:00</published><updated>2009-07-12T16:32:42.560-04:00</updated><title type='text'>More Maps</title><content type='html'>&lt;p&gt;This wasn't intended to be the Google Maps blog. Really. But hey, since they
just released the Keyhole mode, I thought it might be worth going over the
structure of the data.&lt;/p&gt;

&lt;p&gt;Actually the integration of the Keyhole images is quite straightforward. The
only things that had to change were (a) the functions that map between
longitude/latitude pairs and pixel coordinates and (b) the tile URL generator.&lt;/p&gt;

&lt;p&gt;The first of these is very simple. It would appear that the Maps team simply
adhered to the coordinate system already in use by Keyhole, as it's completely
different than the Maps coordinate system. The mapping functions are as
follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Initialize the zoom levels.
//
var gZoomLevels = new Array();
for (var zoom = 0; zoom &amp;amp;lt; 15; zoom++)
  gZoomLevels[zoom] = Math.pow(2, 25 - zoom) / 360;

// Compute the longitude and latitude for a given pixel coordinate.
//
function getLngLat(pixelX, pixelY, zoom) {
  return new Point(
    pixelX / gZoomLevels[zoom] - 180,
    180 - pixelY / gZoomLevels[zoom]
  );
}

// Compute the pixel coordinate for a given longitude and latitude.
//
function getPixelPos(longitude, latitude, zoom) {
  return new Point(
    (longitude + 180) * gZoomLevels[zoom],
    (180 - latitude)  * gZoomLevels[zoom]
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nothing too surprising there. The part that seems to have people scratching
their heads is the image URL format. At first glance, it appears to be a wacky
series of characters with lots of 'q, r, s, and t'. Well, there is a method to
this madness. First, have a look at the de-obfuscated function below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Compute the URL of the tile with the given coordinates.
//   (note that these coordinates are not the same as in the
//    two functions above:  they must be divided by the tile
//    size, which is 256).
//
function tileUrl(x, y, zoom) {
  var range = Math.pow(2, 17 - zoom);

  // Wrap-around x coordinate.
  //
  if ((x &amp;amp;lt; 0) || (x &amp;amp;gt; range - 1)) {
    x = x % range;

    // The mod operator isn't quite the same on a computer as it is
    //   in your math class (negative isn't handled correctly).
    //
    if (x &amp;amp;lt; 0)
      x += range;
  }

  // Build the quadtree path, working our way down from 2^16
  //   to the current zoom level.
  //
  var Ac = "t";
  for (var pow = 16; pow &amp;amp;gt;= zoom; pow--) {
    // Drop to the next zoom level.
    //
    range = range / 2;

    if (y &amp;amp;lt; range) {
      if (x &amp;amp;lt; range) {
        // Upper-left quadrant.
        //
        Ac += "q";
      } else {
        // Upper-right quadrant.
        //
        Ac += "r";
        x -= range;
      }
    } else {
      if (x &amp;amp;lt; range) {
        // Lower-left quadrant.
        //
        Ac += "t";
        y -= range;
      } else {
        // Lower-right quadrant.
        //
        Ac += "s";
        x -= range;
        y -= range;
      }
    }
  }

  return "http://kh.google.com/kh?" + "t=" + Ac;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ok, so my comments were a bit of a giveaway. Basically, it looks like Keyhole
stores its data in a quadtree structure, and the URL describes the 'path'
through the tree to find a given tile. A quadtree, many of you may remember
from your undergraduate graphics class, is a nice little structure for
efficiently storing and accessing large tile arrays. It's particularly
effective when not all areas need to be stored with the same level of detail
(as is clearly the case with Keyhole).&lt;/p&gt;

&lt;p&gt;I won't go into detail on the structure here, as others have already done a
better job of explaining it (just do a Google search on 'quadtree'). For our
purposes, suffice it to say that q, r, s, and t refer to the four quadrants at
each depth in the tree.  Thus, a sequence of these characters uniquely
identifies a tile at some depth.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820191874008652?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820191874008652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820191874008652' title='61 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820191874008652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820191874008652'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/04/more-maps.html' title='More Maps'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>61</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820539871872982</id><published>2005-03-15T16:28:00.001-05:00</published><updated>2009-07-12T16:35:33.637-04:00</updated><title type='text'>Ajax Buzz</title><content type='html'>&lt;p&gt;I've always found it quite interesting how giving something a name seems to
make it "real". Case in point? AJAX. When I first [heard][adpativepath] this
term, I thought to myself, "who really needs a specific term for a mishmash of
technologies that's been around for a long time?" Well, as is often the case, I
misunderestimated the importance of having a mental "handle" for an otherwise
complex concept. And just like &lt;a href="http://www.onlamp.com/"&gt;LAMP&lt;/a&gt;, it's not the specific technologies
that are important (the 'P' in LAMP is heavily overloaded, just as the 'XML' in
AJAX isn't as important as the idea of communicating directly with the server).&lt;/p&gt;

&lt;p&gt;I don't know if I particularly care for the appelation -- particularly the XML
bit -- but that no longer really matters. The name has probably stuck now that
the WSJ has an article that opens with the words "Meet Ajax, the technology
powerhouse." So it's settled, the concept has a name now.&lt;/p&gt;

&lt;p&gt;And I believe it is a good thing that &lt;em&gt;some&lt;/em&gt; kind of name has stuck. For some
time now, I've found that everyone has their own ideas about what "rich" means
to a web application (or if you're more into Flash, an &lt;em&gt;internet&lt;/em&gt; application);
and it just takes too long to try and explain "it's like the difference between
Hotmail and Outlook".&lt;/p&gt;

&lt;p&gt;So now that we have a name, and an "AJAX" application has a specific meaning,
what do we do now? Certainly there is more than one way to approach the
problem. Should I use some sort of framework, or bang out all of the Javascript
by hand? How should I encode my server calls? How should I handle back button
support? What about URL-encoding my application's state? There is a host of
issues like these that need solutions (probably many solutions, depending upon
your needs). It's now time for us to begin gathering the existing solutions to
these problems, and to build new ones, so that we can move the Web far beyond
its current state.&lt;/p&gt;

&lt;p&gt;Should be fun!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820539871872982?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820539871872982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820539871872982' title='46 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820539871872982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820539871872982'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/03/ajax-buzz.html' title='Ajax Buzz'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>46</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820520588081466</id><published>2005-02-12T16:23:00.001-05:00</published><updated>2009-07-12T16:37:19.311-04:00</updated><title type='text'>Making the Back Button Dance</title><content type='html'>&lt;p&gt;It seems that I keep discovering nifty things about Google Maps. I didn't
notice anyone commenting on the details of the way it interacts with the
browser history, but there's one really groovy trick it plays that really adds
to usability.We already know that clicking the back button causes it to display
the results of your previous search. That's certainly helpful, as you don't
lose your search history. If you play with it a bit, however, you may also
notice that it also moves the &lt;strong&gt;map&lt;/strong&gt; to your previous search location as
well. This applies to all of your search history, as you move forwards and
backwards amongst your results. Try it out.&lt;/p&gt;

&lt;h2&gt;But how?&lt;/h2&gt;

&lt;p&gt;If you dig through the DOM a bit (e.g. using Mozilla's DOM Inspector), you will
see that there are three input fields in the hidden IFrame that the application
uses to communicate with the server. At first glance, it doesn't appear that
they're used for much of anything (I myself first dismissed them as an
unfinished attempt to make the application state easily to link to).  If you
look at the application code, you'll see that it stores the current map state
(latitude, longitude, and zoom level) in these fields every time it changes.&lt;/p&gt;

&lt;p&gt;Here's the tricky part. When a search result comes back from the server, the
HTML in which it's wrapped contains yet another set of three empty fields.
When you click back, though, the browser replaces the IFrame contents with its
previous state, &lt;strong&gt;including&lt;/strong&gt; the values that were stored in these fields.
You've probably seen this before in regular web applications, when the browser
tries to maintain the state of forms when it goes back to a cached version.&lt;/p&gt;

&lt;p&gt;So you've clicked the back button, the hidden IFrame contains its previous
state, and the right panel now displays your previous search results. The
application also reaches into these three fields to get the previous map state,
and pans/zooms as necessary to display the map in its previous state as well
(you'll find the code that does this in the application's loadVPage() method).
Voila!&lt;/p&gt;

&lt;h2&gt;Reclaiming the back button&lt;/h2&gt;

&lt;p&gt;I believe that, as more developers build web applications that make good use of
DHTML, we will find tricks like this to be invaluable in maintaining the user
experience. Hopefully, users will be able to depend upon the browser history to
work as advertised -- something we can't often say about most web apps these
days.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820520588081466?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820520588081466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820520588081466' title='44 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820520588081466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820520588081466'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/02/making-back-button-dance.html' title='Making the Back Button Dance'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>44</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820413357936799</id><published>2005-02-11T16:06:00.002-05:00</published><updated>2009-07-12T16:43:51.734-04:00</updated><title type='text'>Still more fun with maps</title><content type='html'>&lt;p&gt;Well, that was certainly an unexpected flood of responses. Apparently I wasn't
the only one that found Google Maps interesting &amp;emdash; I was amazed at some
of the creative hacks that some commentors created. After sifting through this
deluge, I decided to summarize some of the findings, clarify a few points, and
add a few other comments on implementation details. This is kind of a grab bag
of points, so please bear with me.&lt;/p&gt;

&lt;h2&gt;Cut Google some slack on Safari&lt;/h2&gt;

&lt;p&gt;I noticed a lot of people complaining both here and on Slashdot about the lack
of Safari support. And I'm not completely unsympathetic, as I'm running a shiny
new Mac Mini at home that I love. However, as anyone can attest that has ever
tried to build an even remotely complex web application, it just ain't easy.
And please don't blather on about who implements 'web standards' better
&amp;emdash; no one really implements them, and even if they did, you'd still be
outta-luck if you wanted to do anything interesting in DHTML.&lt;/p&gt;

&lt;p&gt;If you take some time to dig through Google's Javascript, you'll find that
there is proto-Safari support all over the place. They're clearly working on
it, and you really can't ask for much more than that.&lt;/p&gt;

&lt;h2&gt;The route overlay&lt;/h2&gt;

&lt;p&gt;There's one really interesting facet of the route display that I totally failed
to notice the first time around &amp;emdash; I was doing everything in Mozilla and
simply didn't notice that they were actually using Microsoft's VML to render
the route on IE. It may be non-standard, but you have to admit that it's very
fast and effective! And switching off between client-side and server-side
rendering in one code base is a pretty cool hack.&lt;/p&gt;

&lt;h2&gt;Decoding polylines and levels&lt;/h2&gt;

&lt;p&gt;Also because I only noticed the server-side route rendering the first time
around, I failed to check whether the route's polylines were being decoded on
the client. Well, as several commentors pointed out, they are. In fact, the
decoding loop is fairly simple (just have a look at &lt;code&gt;decodePolyline()&lt;/code&gt; for the
details). I originally assumed this stream was encoded so that you could just
grab it and send it back to the server for rendering (thus making the image
server stateless, and the rendered route cacheable). However, since they're
decoded on the client, it appears that it also served the purpose of keeping
the size reasonable &amp;emdash; encoding all those points as XML would get pretty
fat.&lt;/p&gt;

&lt;p&gt;I also glossed over the fact that there's another stream associated with the
route called 'levels'. This is an interesting trick that allowed them to encode
the route points at different zoom levels in the same stream (because there's
really no opportunity to easily go back to the server for a new route when you
change zoom levels &amp;emdash; when you're rendering on the client).&lt;/p&gt;

&lt;h2&gt;Flow of control for form submit and IFrame&lt;/h2&gt;

&lt;p&gt;Although it's something of a wacky implementation detail, it's interesting to
note how the search form at the top of the application works. It is actually
contained in a FORM element, although it has three separate DIVs whose
visibilities are swapped as you click on the different search links. However,
it can't be submitted directly, as that would cause the entire application to
reload. Instead, the event handler for the form's submit button suppresses the
reload, gathers the search parameters, and calls the application's &lt;code&gt;search()&lt;/code&gt;
method. This method builds a query URL and sets a hidden IFrame's 'src'
parameter, which causes it to gather a new chunk of XML from the server.&lt;/p&gt;

&lt;p&gt;As I believe I mentioned in the previous article, requesting the XML via this
IFrame has the additional benefit that it ties the browser's history perfectly
to the application's state. Although it would be nice if someone would fix
Mozilla such that the history titles are correct (this works properly in IE).&lt;/p&gt;

&lt;h2&gt;&lt;code&gt;asynchronousTransform()&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;It turns out that Google Maps communicates with the server both through the
hidden IFrame and the XMLHttpRequest object. I mentioned in the last article
that it transforms the downloaded XML using XSL.  Well, that XSL is not
actually hard-coded into the application. Instead, whenever it needs to perform
a transform, it requests the XSL via XMLHttpRequest, performs the transform,
and caches the XSL itself so that it won't need to download it again.&lt;/p&gt;

&lt;h2&gt;Permalink and feedback&lt;/h2&gt;

&lt;p&gt;One of the potential downsides to building an application that runs entirely
within a single page is that the address bar never changes, so it's not
possible for the user to create links to the application's current state. Of
course, many 'normal' web applications don't really work properly when you try
to link to their internal pages, but people have still come to expect it to
work most of the time.&lt;/p&gt;

&lt;p&gt;Google's solution to this problem was to create the 'link to this page' anchor
in the right panel. When you click on it, it refreshes the entire application
with a URL that encodes the entire application state.  Pretty nifty, as it
gives you the important parts of the behavior everyone likes to call 'REST'
without having to break the application up into a million little pieces.&lt;/p&gt;

&lt;p&gt;You may have noticed that the 'feedback' link also encodes the application's
state. The map application actually updates the hrefs of both of the stateful
links every time the application state changes.&lt;/p&gt;

&lt;h2&gt;Profiler&lt;/h2&gt;

&lt;p&gt;Often you can tell quite a bit from code that is left lying around unexecuted.
In this case, it appears that the Google Maps team may have had performance
problems in some methods (or may simply have been trying to head them off). You
can tell this because there are some prologue/epilogue functions being called
in various methods that definitely smell like a hand-rolled profiler. And if
you look at the list of methods that contain these hooks, it definitely makes
sense:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Polyline.decodePolyline()
Polyline.decodeLevels()
Polyline.getVectors()
Page.loadFromXML()
Map.getVMLPathString()
Map.createRawVML()
Map.createVectorSegments()
Map.createImageSegments()
Map.drawDirections()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If this is indeed the case, I think it's worth noting that Mozilla's profiler
actually does a reasonably good job. And although performance on one browser is
not perfectly indicative of performance on the others, the Mozilla results have
been roughly indicative of results on IE in my experience.&lt;/p&gt;

&lt;h2&gt;Tiles &amp;amp; longitude/latitude mapping&lt;/h2&gt;

&lt;p&gt;The mapping of tiles to longitude/latitude pairs is relatively straightforward.
The code for doing transformations in both directions can be found in the
functions &lt;code&gt;getBitmapCoordinate()&lt;/code&gt;, &lt;code&gt;getTileCoordinate()&lt;/code&gt;, and &lt;code&gt;getLatLng()&lt;/code&gt;, and
several commentors have picked apart the transforms in more detail. As
mentioned before, the tiles' image source URLs encode the longitude, latitude,
and zoom level.&lt;/p&gt;

&lt;p&gt;Several commentors also suggested that the entire map was pre-rendered at every
zoom level, so that the web server could simply deliver the tiles without
further consideration. While I believe this is partially true, I also am fairly
certain that some areas will be viewed far more often than others. Clearly,
Google is working from vector data at some level, and it would probably make
far more sense to render tiles on the fly and caching them. This would also
make a big difference when it came to dealing with updates to the vector data,
especially if those updates could be localized such that the entire tile cache
need not be invalidated.&lt;/p&gt;

&lt;h2&gt;Crazy 'bookmarklet'&lt;/h2&gt;

&lt;p&gt;Finally, I have to give kudos to those who've been working on the 'bookmarklet'
that reaches into the running application and makes it dance. It's completely
novel to me that you can add bookmarks of the form 'javascript:' and have them
run in the context of the current page. It makes perfect sense, of course
&amp;amp;emdash; I just never thought of it. It appears that the current state of
the art of this hack can be found &lt;a href="http://libgmail.sourceforge.net/googlemaps.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The only unfortunate part about this (through no fault of the authors') is that
it's likely to be brittle in the face of updates to Google Maps &amp;emdash; the
Javascript has to reach into global variables within the running application,
which will probably change when Google's code obfuscator is run. It does give
us a glimpse of a possible future, however, when even web pages publish public
API's for developers to use. Very interesting!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820413357936799?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820413357936799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820413357936799' title='95 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820413357936799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820413357936799'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/02/still-more-fun-with-maps.html' title='Still more fun with maps'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>95</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116818019991521367</id><published>2005-02-09T09:29:00.001-05:00</published><updated>2009-07-12T20:51:06.417-04:00</updated><title type='text'>Mapping Google</title><content type='html'>&lt;p&gt;By now, many of you will have gone and tried out the new Google Maps
application. By and large, you have to admit that it's pretty damned slick for
a DHTML web application -- even my wife was impressed, and that's not easy with
geek toys. So, in the spirit of Google Suggest and GMail, I've decided to have
a quick peek under the hood to figure out what makes it tick.&lt;/p&gt;

&lt;h2&gt;Not quite like GMail&lt;/h2&gt;

&lt;p&gt;The first thing I noticed is that it doesn't quite work like GMail. Whereas
GMail uses XMLHttp to make calls back to the server, Google Maps uses a hidden
IFrame. Each method has its benefits, as I'll discuss below, but this
difference of approach does seem to imply that it may not be the same team
doing the work.&lt;/p&gt;

&lt;h2&gt;The Graphics&lt;/h2&gt;

&lt;p&gt;Probably the most striking thing about Google Maps is the very impressive (for
DHTML, anyway) graphics. Now, I'm sure that many of you old JavaScript hacks
out there have known this sort of thing was possible for a long time, but it's
very cool to see it (a) actually being used for something real, and (b) where
normal users will see it.&lt;/p&gt;

&lt;p&gt;For those to whom the implementation is less than obvious, here's a quick
breakdown. The top and side bars are (more or less) simply HTML. The center
pane with the map, however, is a different beast. First, let's address the map
itself. It is broken up into a grid of 128x128 images (basically like an old
tile-based scrolling console game). The dragging code is nothing new, but the
cool trick here is that each of these images is absolutely positioned -- and
the 'infinite' scrolling effect is achieved by picking up tiles that are
off-screen on one end and placing them down on the other end. The effect is
kind of like laying track for a train by picking up track from behind it.&lt;/p&gt;

&lt;p&gt;&lt;center&gt;
  &lt;img src="http://photos1.blogger.com/x/blogger/7678/661/320/219085/Tiles.png"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google map, with tiles outlined&lt;/em&gt;
&lt;/center&gt;&lt;/p&gt;

&lt;p&gt;The push-pins and info-popups are a different matter. Simply placing them is no
big trick; an absolutely-positioned transparent GIF does the trick nicely. The
shadows, however, are a different matter. They are PNGs with 8-bit alpha
channels. Personally, I didn't even realize you could depend upon the browser
to render these correctly, but apparently (at least with IE6 and Mozilla), you
can. And they actually render pretty quickly -- for proof, check out the
overlaid route image (at the end of the article), which is often as big as the
entire map view.&lt;/p&gt;

&lt;p&gt;&lt;center&gt;
  &lt;img src="http://photos1.blogger.com/x/blogger/7678/661/320/239629/Pin.gif"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The pushpin, with its two images outlined&lt;/em&gt;
&lt;/center&gt;&lt;/p&gt;

&lt;h2&gt;Communicating with the Server&lt;/h2&gt;

&lt;p&gt;There are two ways in which Google Maps has to communicate with the server. The
first is to get map images, and the second is to get search results. It turns
out that getting map images is remarkably easy -- all you have to do is set an
image tile's URL. Because the coordinate system is known and fixed (each tile
represents a known area specified in longitude and latitude, at a given zoom
level), the client has all the information it needs to set tile URLs. Each tile
URL is of the following form:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://mt.google.com/mt?v=.1&amp;amp;x={x tile index}&amp;amp;{y tile index}=2&amp;amp;zoom={zoom level}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'm not sure what the 'v' argument specifies, but it never seems to change. The
others are fairly self-explanatory. One nice side effect of this is that the
images have fixed URLs for a given chunk of the earth's surface, so they get
cached. If you're doing most of your searches in one region, then the app can
be quite snappy once everything gets cached.&lt;/p&gt;

&lt;p&gt;Doing searches is another matter. Clearly, you can't 'submit' the entire page,
because that would destroy your map and other context. Google's solution is to
submit a hidden IFrame, then gather the search results from it. Let's say, for
example, that you simply wanted to go to Atlanta. You type 'Atlanta' in the
search area, and the following HTTP GET is made:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://maps.google.com/maps?q=atlanta&amp;amp;amp;z=13&amp;amp;sll=37.062500%2C-95.677068&amp;amp;sspn=37.062500%2C80.511950&amp;amp;output=js
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are a couple of things to notice here. The 'question' is passed in the
'q' parameter (much like Google). The other arguments are 'z' for zoom, 'sll'
for longitude &amp;amp;amp;amp;amp;amp;amp;amp; latitude (your current focus, I
believe), and 'sspn' to specify the span/size of your viewing area. What's
interesting is what comes back:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta http-equiv="content-type" content="text/html; charset=UTF-8"/&amp;gt;
    &amp;lt;title&amp;gt;Google Maps - atlanta&amp;lt;/title&amp;gt;
    &amp;lt;script type="text/javascript"&amp;gt;
    //&amp;lt;![CDATA[
    function load() {
      if (window.parent &amp;amp;amp;&amp;amp; window.parent._load) {
        window.parent._load({big chunk of XML}, window.document);
      }
    }
    //]]&amp;gt;
    &amp;lt;/script&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body onload="load()"&amp;gt;
    &amp;lt;input id="zoom" type="text" value=""/&amp;gt;
    &amp;lt;input id="centerlat" type="text" value=""/&amp;gt;
    &amp;lt;input id="centerlng" type="text" value=""/&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This HTML is loaded into the hidden IFrame which, when loaded, will punt a big
chunk of XML back up to the outer frame's _load() function. This is kind of a
cool trick, because it saves the outer frame from having to determine when the
IFrame is done loading.&lt;/p&gt;

&lt;p&gt;I mentioned before that there was some advantage to be had by using a hidden
IFrame over making direct XMLHttp requests. One of these is that the IFrame's
state affects the back button. So every time you do a search, it creates a new
history entry. This creates an excellent user experience, because pressing the
back button always takes you back to the last major action you performed (and
the forward button works just as well).&lt;/p&gt;

&lt;h2&gt;Big Hunks of XML&lt;/h2&gt;

&lt;p&gt;Ok, so now the outer frame's code has a big chunk of XMl. What can it do with
that? Well, it turns out that Google Maps depends upon two built-in browser
components: XMLHttpRequest and XSLTProcessor. Oddly enough, even though it
doesn't use XMLHttpRequest for making calls to the server, it &lt;em&gt;does&lt;/em&gt; use it for
parsing XML. I'll get to the XSLT later.&lt;/p&gt;

&lt;p&gt;Here's an example of the XML response that comes back from the 'Atlanta'
request above:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;?xml version="1.0"?&amp;gt;
&amp;lt;page&amp;gt;
  &amp;lt;title&amp;gt;atlanta&amp;lt;/title&amp;gt;
  &amp;lt;query&amp;gt;atlanta&amp;lt;/query&amp;gt;
  &amp;lt;center lat="33.748889" lng="-84.388056"/&amp;gt;
  &amp;lt;span lat="0.089988" lng="0.108228"/&amp;gt;
  &amp;lt;overlay panelStyle="/mapfiles/geocodepanel.xsl"&amp;gt;
    &amp;lt;location infoStyle="/mapfiles/geocodeinfo.xsl" id="A"&amp;gt;
      &amp;lt;point lat="33.748889" lng="-84.388056"/&amp;gt;
      &amp;lt;icon class="noicon"/&amp;gt;
      &amp;lt;info&amp;gt;
        &amp;lt;title xml:space="preserve"&amp;gt;&amp;lt;/title&amp;gt;
        &amp;lt;address&amp;gt;
          &amp;lt;line&amp;gt;Atlanta, GA&amp;lt;/line&amp;gt;
        &amp;lt;/address&amp;gt;
      &amp;lt;/info&amp;gt;
    &amp;lt;/location&amp;gt;
  &amp;lt;/overlay&amp;gt;
&amp;lt;/page&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nothing surprising here -- we have a title, query, center &amp;amp; span, and the
location and name of the search result. For a slightly more interesting case,
let's look at the response when searching for 'pizza in atlanta':&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;pre&amp;gt;
&amp;lt;?xml version="1.0" ?&amp;gt;
&amp;lt;page&amp;gt;
  &amp;lt;title&amp;gt;pizza in atlanta&amp;lt;/title&amp;gt;
  &amp;lt;query&amp;gt;pizza in atlanta&amp;lt;/query&amp;gt;
  &amp;lt;center lat="33.748888" lng="-84.388056" /&amp;gt;
  &amp;lt;span lat="0.016622" lng="0.017714" /&amp;gt;
  &amp;lt;overlay panelStyle="/mapfiles/localpanel.xsl"&amp;gt;
    &amp;lt;location infoStyle="/mapfiles/localinfo.xsl" id="A"&amp;gt;
      &amp;lt;point lat="33.752099" lng="-84.391900" /&amp;gt;
      &amp;lt;icon image="/mapfiles/markerA.png" class="local" /&amp;gt;
      &amp;lt;info&amp;gt;
        &amp;lt;title xml:space="preserve"&amp;gt;Kentucky Fried Chicken/Taco Bell/&amp;lt;b&amp;gt;Pizza&amp;lt;/b&amp;gt; Hut&amp;lt;/title&amp;gt;
        &amp;lt;address&amp;gt;
          &amp;lt;line&amp;gt;87 Peachtree St SW&amp;lt;/line&amp;gt;
          &amp;lt;line&amp;gt;Atlanta, GA 30303&amp;lt;/line&amp;gt;
        &amp;lt;/address&amp;gt;
        &amp;lt;phone&amp;gt;(404) 658-1532&amp;lt;/phone&amp;gt;
        &amp;lt;distance&amp;gt;0.3 mi NW&amp;lt;/distance&amp;gt;
        &amp;lt;description&amp;gt;
          &amp;lt;references count="9"&amp;gt;
            &amp;lt;reference&amp;gt;
              &amp;lt;url&amp;gt;http://www.metroatlantayellowpages.com/pizzaatlanta.htm&amp;lt;/url&amp;gt;
              &amp;lt;domain&amp;gt;metroatlantayellowpages.com&amp;lt;/domain&amp;gt;
              &amp;lt;title xml:space="preserve"&amp;gt;Atlanta&amp;lt;b&amp;gt;Pizza&amp;lt;/b&amp;gt; Guide-Alphabetical Listings of Atlanta&amp;lt;b&amp;gt;...&amp;lt;/b&amp;gt;&amp;lt;/title&amp;gt;
            &amp;lt;/reference&amp;gt;
          &amp;lt;/references&amp;gt;
        &amp;lt;/description&amp;gt;
        &amp;lt;url&amp;gt;http://local.google.com/local?q=pizza&amp;amp;near=atlanta&amp;amp;amp;amp;amp;amp;amp;amp;amp;latlng=33748889,-84388056,11825991348281990841&amp;lt;/url&amp;gt;
      &amp;lt;/info&amp;gt;
    &amp;lt;/location&amp;gt;
    { lots more locations... }
  &amp;lt;/overlay&amp;gt;
&amp;lt;/page&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, nothing too surprising when you think about the data that's going to
show in the map pane. But how do the results get shown in the search result
area to the right? This is where things get a little wacky. The JavaScript
actually uses the XSLTProcessor component I mentioned earlier to apply an XSLT
to the result XML. This generates HTML which is then shown in the right panel.
We've come to expect this sort of thing on the server, but this is the first
time I've ever seen it done on the client (I'm sure it saves Google lots of
cycles, but personally I didn't even know XSLTProcessor existed!)&lt;/p&gt;

&lt;h2&gt;Driving Directions&lt;/h2&gt;

&lt;p&gt;There's one last case to discuss, and that's driving directions. This works
just like other searches, including XSLT to show the results, with one
exception: the result XML includes a &lt;polyline&gt; tag that two opaque values
encoding the geometric route to be taken. This data appears to be base 64
encoded (or something similar, anyway). Remember the giant transparent PNG I
mentioned earlier for rendering routes? This data is used to render that
sucker. The data looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;polyline numLevels="4" zoomFactor="32"&amp;gt;
  &amp;lt;points&amp;gt;k`dmEv`naOdGC??EtD??@|DAxL??hEFjJ@ ...&amp;lt;/points&amp;gt;
  &amp;lt;levels&amp;gt;BBB???BB?BB??@??@?????BB??@?????@? ...&amp;lt;/levels&amp;gt;
&amp;lt;/polyline&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This polyline data is then used to request the route PNG from the server using
a URL like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://www.google.com/maplinedraw?width=324&amp;amp;height=564&amp;amp;path=sRS?k@fB@?}As@e@CGAIA}@BwCEu@Bs@?E_@cACS@a@PaC ...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;center&gt;
  &lt;img src="http://photos1.blogger.com/x/blogger/7678/661/320/118745/Route.png"/&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The route overlay&lt;/em&gt;
&lt;/center&gt;&lt;/p&gt;

&lt;h2&gt;In Summary&lt;/h2&gt;

&lt;p&gt;That's about it. I hope that demystifies this application a bit; the real
magic, of course, is all the work going on to enable this on the back-end. The
fact that Google's servers can handle all of these images requests, route
finding, line drawing, searches and the like so quickly is the real magic. I
also want to point out that their map renderer (or the one they purchased)
works &lt;em&gt;much&lt;/em&gt; better than all the other ones I've seen on Mapquest, Mapblast,
and the like. That alone makes it worth using, if only so you can actually
&lt;em&gt;read&lt;/em&gt; the map!&lt;/p&gt;

&lt;p&gt;I also think it bears noting that Google is pulling out all the stops to build
rich web apps, no matter how weirdly they have to hack the browser to make them
go. And I strongly believe that this is a trend that is here to stay -- XHTML
Strict/CSS/etc be damned. At the end of the day, what really matters to users
is compelling apps that let them get their work done quickly.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116818019991521367?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116818019991521367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116818019991521367' title='490 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116818019991521367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116818019991521367'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/02/mapping-google.html' title='Mapping Google'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>490</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820742841446360</id><published>2005-01-02T16:55:00.001-05:00</published><updated>2009-07-12T20:59:33.520-04:00</updated><title type='text'>DHTML Leaks Like a Sieve</title><content type='html'>&lt;h2&gt;Most web browsers leak memory like a bloody sieve&lt;/h2&gt;

&lt;p&gt;You heard me: Like a sieve. Gobs and gobs of memory. Necessarily. "Gee, that's
funny", you might say, "My browser doesn't seem to leak noticably". And you're
probably right. However, the design of both major browsers (Internet Explorer
and Mozilla) leaks memory &lt;em&gt;necessarily&lt;/em&gt; (To be honest, I'm not sure about
Safari and Opera, but it wouldn't surprise me).&lt;/p&gt;

&lt;p&gt;Let's take a moment to think about that "necessarily" part.  What I mean by
this is that these browsers are &lt;em&gt;not&lt;/em&gt; poorly implemented (I'm not going to pass
judgment on that), but rather that their design leads inexorably to memory
leaks. The reason you don't usually see this when browsing is that (a) most
individual pages are simple enough so as not to exhibit the leak and (b) the
few sites that use truly heavy JavaScript often work very hard to get around
these leaks.&lt;/p&gt;

&lt;p&gt;If you've ever built a really complex site using lots of JavaScript, you've
probably seen this problem. You may even have some idea of where it comes from.
Well, I'm writing this explanation because (a) I think I fully understand the
problem and (b) there are a lot of confused (or simply wrong) explanations out
there.&lt;/p&gt;

&lt;h2&gt;The Joy of Automatic Garbage Collection&lt;/h2&gt;

&lt;p&gt;The problem is not JavaScript.  Nor is it really the DOM.  It is the
&lt;em&gt;interface&lt;/em&gt; between the two. JavaScript uses (sometime after Netscape 2.0, I
think) a fully garbage-collected memory allocator. For anyone who doesn't
understand this, this simply means that memory can &lt;em&gt;never&lt;/em&gt; be truly leaked,
even when objects reference each other circularly (e.g. A-&amp;gt;B-&amp;gt;A). Both
Internet Explorer and Mozilla are built on roughly similar component models for
their native object layer (i.e.  the DOM). Internet Explorer uses the native
windows COM model, while Mozilla uses a very similar XPCOM model. One of the
things these two models have in common is that objects allocated within them
are &lt;em&gt;not&lt;/em&gt; garbage collected &amp;amp;emdash; they are reference counted.  Again,
for those unfamiliar with the vagaries of memory management systems, this means
that objects might &lt;em&gt;not&lt;/em&gt; get freed if they take part in a circular reference
(as above).&lt;/p&gt;

&lt;p&gt;Now the designers of these browsers have gone to some trouble to keep their COM
layers (I'll refer to both as COM for simplicity) from leaking during normal
usage. If you're careful, this is not too difficult &amp;amp;emdash; you simply
have to be vigilant about potential circular references and use various hacks
to refactor them out of existence. And of course their JavaScript garbage
collectors can't really leak at all.  Where things start to go sour is when you
have circular references that involve both* JavaScript objects and COM objects.
Let me use an example to illustrate this point. Let's say you have a JavaScript
object 'jsComponent' with a reference to an underlying DIV. And the DIV
contains a reference to the jsComponent object. It might look something like
this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var someDiv = document.getElementById('someDiv');
jsComponent.myDomObject = someDiv;
someDiv.myComponent = jsComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What's wrong with this? What basically appears to happen is that jsComponent
holds a reference to someDiv. In a reference-counted memory manager, this means
that it has a reference count of at least 1, and thus cannot be freed. Now
someDiv also holds a reference to jsComponent (because jsComponent &lt;em&gt;cannot&lt;/em&gt; be
freed if it is still accessible via someDiv, or things could go &lt;em&gt;really&lt;/em&gt; bad).
Because COM objects cannot truly participate in garbage collection, they must
create a 'global' reference to myComponent (I'm not sure what the actual
implementation looks like under the hood, because I haven't dug through the
source for either browser, but I imagine it's similar to the semantics of
Java's createGlobalRef() JNI call).  Thus begins the deadly embrace: someDiv's
reference count will stay at 1 as long as jsComponent is not freed, but
jsComponent will not be freed until someDiv drops its global reference to it.
Game over: that memory is irretrievable without human intervention.&lt;/p&gt;

&lt;p&gt;At this point, you might be asking yourself how common circular references of
this sort really are. First, I would argue that they &lt;em&gt;ought&lt;/em&gt; to be relatively
common, because building any sort of reusable component framework in JavaScript
requires this sort of structure to tie the component and DOM layers together.
However, there are many schools of thought on this subject, and if that were
the only problem, it wouldn't be so bad. However, there are two very common
cases that make this problem much more notable.&lt;/p&gt;

&lt;h2&gt;Event Handlers&lt;/h2&gt;

&lt;p&gt;Perhaps the most common manifestation is in DOM event handlers. Most event
handlers take the form " onclick='this.doSomething()' ". This doesn't really
pose a problem. However, if the event handler references a JavaScript object in
any way (as in the aforementioned component scenario), then it serves as a
back-reference. This is why, in many posts and articles I've read about
avoiding memory leaks, the statement "don't forget to unhook all of your event
handlers" is often made.&lt;/p&gt;

&lt;h2&gt;Closures&lt;/h2&gt;

&lt;p&gt;A much more subtle (and therefore nasty) situation where circular references
occur is in JavaScript closures. For those not familiar with the concept, a
closure binds stack variables to an object created in a local scope. You may
well have used them before without realizing it.  For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function foo(buttonElement, buttonComponent) {
  buttonElement.onclick = new function() {
    buttonComponent.wasClicked();
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At first glance, it may appear that this method of hooking events on a button
avoids the circular reference problem. After all, the button's 'onclick' event
doesn't directly reference any JavaScript object, and the button element itself
contains no such reference. So how does the event find its way back to the
component? The answer is that JavaScript creates a closure that wraps the
anonymous function and the local variables (in this case, 'buttonElement' and
'buttonComponent'). This allows the code in the anonymous function to call
buttonComponent.wasClicked().&lt;/p&gt;

&lt;p&gt;Unfortunately, this closure is an implicitly created object that closes the
circular reference chain containing both the JavaScript button component and
the DOM button element. Thus, the memory leak exists here as well.&lt;/p&gt;

&lt;h2&gt;So Now What?&lt;/h2&gt;

&lt;p&gt;Unfortunately, there really is no easy way around this problem. If you want to
build complex reusable objects in JavaScript, you are probably going to have to
deal with this and some point. And don't feel tempted to think "It's probably
not &lt;em&gt;that&lt;/em&gt; bad; I'll just ignore it" -- neither Internet Explorer nor Mozilla
free these objects even &lt;em&gt;after&lt;/em&gt; a page is unloaded, so the browser will just
blow more and more memory.  In fact, I first noticed this problem in my own
work when I saw IE blowing around 150 megabytes of memory!&lt;/p&gt;

&lt;p&gt;The only real option I know of is to be extremely careful to clean up potential
circular references. This can be a little tricky if you're writing components
for others to use, because you have to ensure that they call some cleanup
method in the 'onunload' event. But at least by understanding the root cause of
the problem, you have at least some hope of getting your leaks cleaned up
before your users start complaining!&lt;/p&gt;

&lt;h2&gt;One Further Note&lt;/h2&gt;

&lt;p&gt;When I said at the beginning of this article that the design of most web
browsers &lt;em&gt;necessarily&lt;/em&gt; leaks, I was probably making too strong a statement.
While their reference-counting and mark-and-sweep garbage collection
implementations do not "play well" together, there is &lt;em&gt;lots&lt;/em&gt; of research on
this subject out there, and I'm sure a way could be found to fix this problem
without throwing away most of the implementation.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820742841446360?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820742841446360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820742841446360' title='180 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820742841446360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820742841446360'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2005/01/dhtml-leaks-like-sieve.html' title='DHTML Leaks Like a Sieve'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>180</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14995055.post-116820646193979811</id><published>2004-12-20T16:39:00.003-05:00</published><updated>2009-07-12T21:07:59.740-04:00</updated><title type='text'>The Insanity of HTTP Compression</title><content type='html'>&lt;p&gt;If you've dealt with HTTP much, you've probably at least &lt;em&gt;heard&lt;/em&gt; that it
supports gzip compression. And under some circumstances, this even turns out to
be true! You might think that supporting something as simple as decoding
gzip-encoded content would be simple and straightforward, and you'd be right
(especially given that gzip code has been available freely since, well, about
forever).&lt;/p&gt;

&lt;p&gt;It seems, however, that people working on most major browsers at various points
found ways to make this difficult. It would be one thing (albeit a silly thing)
if they simply didn't support gzip encoding, but it's another matter entirely
that a number of browsers &lt;em&gt;request&lt;/em&gt; encoded content which they then proceed to
barf on. There are lots of articles out there describing, in varying degrees of
detail, the mess that is HTTP compression. IBM has a &lt;a href="http://www-106.ibm.com/developerworks/web/library/wa-httpcomp/"&gt;good one&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;The Specific Problem&lt;/h2&gt;

&lt;p&gt;Myself, I don't have much cause to worry about this, except for one very
specific scenario: various difficult-to-discern versions and patches of
Internet Explorer do not &lt;em&gt;cache&lt;/em&gt; compressed content correctly. Case in point:
if you reference an external .js file that IE then caches, it will usually
screw it up the &lt;em&gt;second&lt;/em&gt; time you hit the page. It appears that what's
happening is that it somehow forgets the full size of the compressed .js file
in its cache, truncating the decompressed .js file to its &lt;em&gt;compressed&lt;/em&gt; size.
Needless to say, this is not exactly conducive to your script actually working
at all.&lt;/p&gt;

&lt;p&gt;I don't know about you, but I've seen some pretty damned big external scripts
out there (think hundreds of kilobytes, uncompressed), and it would be a real
waste to &lt;em&gt;not&lt;/em&gt; be able to compress these things. But no matter how hard I
tried, I was never able to reliably detect the versions of IE that do and do
not handle this correctly (and to make matters worse, the most commonly
deployed versions &lt;em&gt;don't&lt;/em&gt;, so it's kind of moot if you want to see any
real-world benefit).&lt;/p&gt;

&lt;h2&gt;My Wacky Solution&lt;/h2&gt;

&lt;p&gt;But I'm going to share a trick with you.  It's &lt;em&gt;really&lt;/em&gt; not pretty, but quite
functional in practice. If you want to compress external scripts reliably, what
you need to do is wrap 'em up in HTML and shove 'em into an IFrame. I see by
that incredulous look on your face that you think this is a strange idea.
Doesn't this mess with my &lt;code&gt;window&lt;/code&gt; references?  You bet it does, but if you
make them all &lt;code&gt;parent&lt;/code&gt; references, then everything works out just fine.&lt;/p&gt;

&lt;p&gt;Basically, all you have to do is embed an IFrame in your HTML, like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;iframe id="__scriptFrame" style="display: none;" src="bigAssScript.js"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then you can access functions in your IFrame like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var scriptFrame = document.getElementById('__scriptFrame');
scriptFrame.contentWindow.foo();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are two caveats that spring to mind when doing this. First, you can't set
your parent window's event handlers from within the external script. However,
this is easily fixed by creating a method within the outer HTML that allows the
external script to set these handlers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function setWindowOnResize(handler) {
  window.onresize = handler;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The other caveat is that you need to ensure that the IFrame is done loading
before you try to access any methods within it. This is also relatively easy to
fix: use the IFrame's &lt;code&gt;onload&lt;/code&gt; handler to handle any startup code you need to
run. This simply avoids the problem, because this event will not fire until the
IFrame is done loading -- and the IFrame won't finish loading until after the
&lt;em&gt;outer&lt;/em&gt; window is done loading.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;do&lt;/em&gt; realize that this is a really strange solution, but once you
implement it, it's pretty easy to maintain, and most importantly it lets you
compress those giant scripts, usually to about 1/5 of their original size. That
can be a pretty significant bandwidth savings!&lt;/p&gt;

&lt;p&gt;To give you an idea of the kinds of savings we're talking about, one of my own
external scripts was compressed from 140,769 bytes to 29,057 bytes, for a
compression ratio of nearly 80%. If you consider the fact that external .js
files almost &lt;em&gt;never&lt;/em&gt; get compressed normally, this will add up
quickly.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14995055-116820646193979811?l=blog.j15r.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.j15r.com/feeds/116820646193979811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14995055&amp;postID=116820646193979811' title='24 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820646193979811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14995055/posts/default/116820646193979811'/><link rel='alternate' type='text/html' href='http://blog.j15r.com/2004/12/insanity-of-http-compression.html' title='The Insanity of HTTP Compression'/><author><name>Joel Webber</name><uri>https://profiles.google.com/111111598146968769323</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-fiMv_Zyxto0/AAAAAAAAAAI/AAAAAAAAS-8/LUZJ460YO9A/s512-c/photo.jpg'/></author><thr:total>24</thr:total></entry></feed>
