<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>John Resig</title>
	
	<link>http://ejohn.org</link>
	<description>Blog, Projects, and Links</description>
	<lastBuildDate>Mon, 09 Jan 2012 22:31:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/JohnResig" /><feedburner:info uri="johnresig" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>42.381929</geo:lat><geo:long>-71.099084</geo:long><image><link>http://ejohn.org/</link><url>http://ejohn.org/files/jeresig-wordpress-sm.jpg</url><title>John Resig (ejohn.org)</title></image><feedburner:emailServiceId>JohnResig</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><item>
		<title>JavaScript as a First Language</title>
		<link>http://ejohn.org/blog/javascript-as-a-first-language/</link>
		<comments>http://ejohn.org/blog/javascript-as-a-first-language/#comments</comments>
		<pubDate>Wed, 21 Dec 2011 19:04:28 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5792</guid>
		<description><![CDATA[At Khan Academy we've been investigating teaching Computer Science to students in some new and interesting ways. The most interesting aspect of which is that we're likely going to be teaching them JavaScript as their first language. We're in a very unique position as we're primarily aiming to teach students who've been through our previous [...]]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://www.khanacademy.org/">Khan Academy</a> we've been investigating teaching Computer Science to students in some new and interesting ways. The most interesting aspect of which is that we're likely going to be teaching them JavaScript as their first language.</p>
<p>We're in a very unique position as we're primarily aiming to teach students who've been through our previous <a href="http://www.khanacademy.org/exercisedashboard?k">math and science-centric curriculum</a>. Because of this we can create some rather compelling exercises and projects that never would've been feasible otherwise.</p>
<p>The prospect of teaching the JavaScript language as a first language is actually really exciting. Teaching prototypal inheritance to experienced classical-inheritance-using developers is normally rather frustrating (and results in many libraries springing up attempting to replicate the classical style of inheritance in JavaScript, which is a whole realm of weirdness in-and-of itself). Teaching prototypal inheritance to someone who has never seen any form of inheritance before will decidedly be an easier task. The same goes for learning functional programming. JavaScript is a great language for experiencing functional programming and can be a major focus of our curriculum as a result.</p>
<p>As we've begun to look at the prospect of JavaScript-as-a-first-language a number of obvious warts stick out (as is obvious to anyone who has worked with JavaScript for any duration). To make sure that general warts don't crop up we will be using some form of linting (either JSLint or JSHint or similar) in the code editor to give the users contextual information on what's happening with their code and why they should be writing their code in a certain way.</p>
<p>We want to go beyond basic syntax tweaks though and find ways of using the language that'll result in an easier learning experience. In particular there are two changes which will likely result in a much simpler on-ramp to learning.</p>
<p><strong>Note:</strong> These particular recommendations really only make sense if you're teaching JavaScript to someone who has never seen the language before and is really only programming with a set of specific, well-coded, libraries. Obviously more will have to be taught in order bring the students up to the level of "see any random piece of cross-browser JavaScript code and understand what it does."</p>
<h3>Type Coercion</h3>
<p>Type coercion is just a complete mess, as many many others have pointed out and as what Douglas Crockford typically teaches, as in <a href="http://www.amazon.com/gp/product/0596517742/ref=as_li_ss_tl?ie=UTF8&#038;tag=jspro-20&#038;linkCode=as2&#038;camp=1789&#038;creative=390957&#038;creativeASIN=0596517742">JavaScript: The Good Parts</a>.</p>
<p>It might make sense to discuss it far later in the education cycle... like after learning about prototypes, functional programming, and closures. Basically after everything that's actually important.</p>
<div class="syntax_hilite">
<div id="js-3">
<div><span style="color: #000066;">name</span> === <span style="color: #3366CC;">"John"</span></div>
</div>
</div>
<p>The first change that I'm recommending is that the students will only ever see, and use, <code>===</code> (and <code>!==</code>). While using '<code>==</code>' does have the advantage of being syntactically shorter there is so much type coercion baggage attached to it as to make it an exercise in futility to try and teach early on in the learning of programming.</p>
<p>The one exception that might be worthwhile to teach later on is the case in which you wish to see if a variable contains a null or undefined value. This can be done easily with a simple <code>someVar == null</code> check and is likely the one useful case of <code>==</code>. (Another noted exception is the browser bug in IE where <code>===</code> checks against Window objects will always return false, but it's unlikely that we'll cover such specific browser issues in our curriculum.)</p>
<p><strong>Falsy Values</strong></p>
<p>For the same reasons that <code>==</code> can be messy, so can falsy values. Enforcing strict boolean checks would result in less edge cases but would certainly result in longer code. Perhaps education of falsy values can be limited to booleans, null, and undefined with number and string falsy values left for a later exercise. </p>
<h3>Function Declarations</h3>
<p>Perhaps the most interesting change that we can make is a rather subtle one, but it's eschewing normal function declarations for creating anonymous functions and assigning them to a variable.</p>
<div class="syntax_hilite">
<div id="js-4">
<div><span style="color: #009900; font-style: italic;">// Don't do this:</span><br />
<span style="color: #003366; font-weight: bold;">function</span> getData<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span> <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p><span style="color: #009900; font-style: italic;">// Do this instead:</span><br />
<span style="color: #003366; font-weight: bold;">var</span> getData = <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span> <span style="color:#008800; font-weight:bold;">&#125;</span>;</div>
</div>
</div>
<p>There are a number of good habits that are instilled when you use this particular technique.</p>
<ul>
<li>Makes it easier to understand "functions as an object". I've found that when you show new developers a function being assigned to a variable it suddenly becomes much more obvious that a function is actually an object and can be manipulated as such (and that a function can be passed as an argument to another function). Thus students are advanced along the path towards a better understanding of functional programming.</li>
<li>It enforces good semicolon habits. Traditional function declaration is the only situation in which semicolons aren't needed (save for conditional statements and loops, naturally) and it makes it much more obvious when they're required all the time.</li>
<li>Doesn't have much of the baggage <a href="https://developer.mozilla.org/en/JavaScript/Reference/Scope_Cheatsheet">traditionally associated with functions and scope</a>.</li>
</ul>
<h3>Block Scope</h3>
<p>This is the remaining area that'll certainly be a challenge for any introductory student to understand and yet I don't see a particularly good solution here. The issue of variables declared within for loops hoisting up is more than enough to make most developers heads spin. I'll have to see if we can't come up with some intuitive ways of explaining how variable declaration works (and combining it with vigilant lint enforcement) rather than having a purely technical solution.</p>
<p>(While <code>(function(){ ... })();</code> is a solution I'm skeptical that we'll be able to teach that early-enough on as to make it worthwhile.)</p>
<h2>JavaScript as a  First Language</h2>
<p>It should be noted that while we're starting with JavaScript as a first language - largely due to its ubiquity, desirability in the larger workforce, lack of prior installation requirements, and ability to create something that's easy to share with friends - we're not going to be myopic and only focus on JavaScript. There are so many things that can be learned from other languages, not to mention entire skillsets that aren't terribly relevant to in-browser JavaScript, that it behooves us to try and bring as much of them into our curriculum as possible.</p>
<p>I talk a little bit more about our choice to use JavaScript and some of the browsers that we'll want to support in our development in the <a href="http://www.youtube.com/watch?v=k0Fi8EnSInE">following video</a>:</p>
<p><iframe width="640" height="360" src="http://www.youtube.com/embed/k0Fi8EnSInE" frameborder="0" allowfullscreen></iframe></p>
<p>By all accounts I want to try and avoid any features that would cause cross-browser weirdness to spring up. As a result we'll be making extensive use of libraries (for drawing to a canvas or manipulating the DOM) and using only JavaScript language features that work consistently in the browsers that we end up supporting.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/Y4CgYR4Z4bc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/javascript-as-a-first-language/feed/</wfw:commentRss>
		<slash:comments>82</slash:comments>
		</item>
		<item>
		<title>Khan Exercise Rewrite</title>
		<link>http://ejohn.org/blog/khan-exercise-rewrite/</link>
		<comments>http://ejohn.org/blog/khan-exercise-rewrite/#comments</comments>
		<pubDate>Thu, 28 Jul 2011 19:33:22 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5786</guid>
		<description><![CDATA[Today we're pushing live a complete rewrite of the Khan Academy Exercise framework (live demo). A big push at Khan Academy has been to write more-and-more exercises for students to practice with. Naturally, to increase the number of exercises that we have, we needed to make it easier for team members, and casual committers, to [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/jeresig/5984905975/" title="Khan Exercise Framework Deployed by John Resig, on Flickr"><img src="http://farm7.static.flickr.com/6144/5984905975_1f9b68ff98_m.jpg" width="240" height="150" alt="Khan Exercise Framework Deployed" style="float:right;margin:0 0 10px 10px;"></a></p>
<p>Today we're pushing live a complete rewrite of the <a href="https://github.com/Khan/khan-exercises">Khan Academy Exercise framework</a> (<a href="http://khanacademy.org/exercisedashboard">live demo</a>).</p>
<p>A big push at <a href="http://khanacademy.org/">Khan Academy</a> has been to write more-and-more exercises for students to practice with. Naturally, to increase the number of exercises that we have, we needed to make it easier for team members, and casual committers, to write them.</p>
<p>When I was first looking in to Khan Academy I did a bunch of digging through their code base (<a href="https://khanacademy.kilnhg.com/Repo/Website/Group/stable/Files">which is Open Source</a>) and noticed that a lot of effort was going in to writing exercises. Interestingly all the exercises were being written in pure JavaScript and were dependent upon the server component in order to run properly. To me this seemed like a massive barrier to entry.</p>
<h2>Brand New Framework</h2>
<p>When I started just over two months ago I immediately went about rewriting the framework to use semantic HTML and not rely upon any server-side components whatsoever. To provide an example of the change that was made here is one particular exercise, Significant Figures 1, <a href="https://khanacademy.kilnhg.com/Repo/Website/Group/stable/File/javascript/exercises/significant_figures_1.js?rev=tip">written for the old framework</a> and <a href="https://github.com/Khan/khan-exercises/blob/master/exercises/significant_figures_1.html">written for the new framework</a>. You can view <a href="http://khanacademy.org/exercises?exid=significant_figures_1">the live version</a> of the exercise, as well.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5985482092/" title="Khan Exercise Code Comparison by John Resig, on Flickr"><img src="http://farm7.static.flickr.com/6012/5985482092_58971521ca.jpg" width="206" height="500" alt="Khan Exercise Code Comparison"></a><br/>Significant Figures 1 went from 191 lines of code down to 58.</center></p>
<p>Note the dramatic lack of "code" - most logic is encapsulated and reduced to a series of variable declarations (some with minimal logic). Additionally utility functions were made significantly more useful, and generic, shared across exercises (some of this was done in the old framework but a complete rewrite allowed us to find areas of obvious overlap).</p>
<p>The result of the new framework is an interesting mix of semantic markup and logic - wrapped in a form of highly specialized templating. Tons of details regarding the specifics of the framework can be found in the <a href="https://github.com/Khan/khan-exercises/wiki/Writing-Exercises:-Home">Writing Exercises tutorial</a>.</p>
<p>In short, some of the cool new features of this framework include:</p>
<ul>
<li>A full module system for dynamically loading specific utilities (such as graphing).</li>
<li>A <a href="https://github.com/Khan/khan-exercises/blob/master/utils/tmpl.js">brand new templating framework</a>, including templating inheritance, that makes it easy to reduce repeated code in exercises (<a href="https://github.com/Khan/khan-exercises/wiki/Writing-Exercises:-Formatting">some examples</a>).</li>
<li>A <a href="https://github.com/Khan/khan-exercises/blob/master/utils/graphie.js">brand new graphing framework</a> (written by Ben Alpert, named 'Graphie') that's built on top of Raphael. This framework provides a simple API for creating all sorts of graphs and charts, it's used extensively throughout the exercises.</li>
<li>An extensible plugin system for creating new <a href="https://github.com/Khan/khan-exercises/wiki/Writing-Exercises:-Answer-Types">answer types</a> (to expand beyond basic multiple choice or fill in the blank).</li>
</ul>
<p>Of course, that's saying nothing of the actual user interaction as well. Most of the new framework's logic is contained on the client-side and is generated directly off of <a href="https://github.com/Khan/khan-api">Khan Academy's REST API</a>.</p>
<p>By moving logic to the client-side we're able to have a much more interactive experience (doing all problem generation on the client-side, doing Ajax-y background submissions, things of that sort).</p>
<h2>Testing</h2>
<p>A big concern for us, with this rewrite, was to ensure that the quality and integrity of exercises was maintained well into the future. We wanted to make sure that the content of the exercises were correct and that regressions do not occur over time.</p>
<p>In fact we have three levels of testing:</p>
<ol>
<li>We have <a href="https://github.com/Khan/khan-exercises/tree/master/utils/test">unit tests for our modules and utility functions</a> (ensures that stuff like the templating will continue to work correctly).</li>
<li>We have an interactive interface for generating <a href="https://github.com/Khan/khan-exercises/tree/master/test/exercises">unit tests</a> for any given exercise (details below).</li>
<li>We have a "Report a Problem" interface for sending post-deployment issues directly to our bug tracker.</li>
</ol>
<p>The second stage is particularly interesting. On a fundamental level it's hard to unit test something as complex as an exercise. While we can ensure that they still work at a functional level we can't verify if the problems make sense, or if graphs look correct, or if it's even possible to pick the right answer.</p>
<p>For these reasons we've introduced a new testing interface in which we use human developers as unit testers. When in test mode an additional panel is displayed asking the user to provide additional details regarding wether the problem is working correctly, or not. <a href="https://github.com/Khan/khan-exercises/wiki/Testing-Exercises">We ask them</a> to really dig into the exercises and make sure that they're working correctly, hints are being displayed properly, and other things of that nature.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5985481938/" title="Khan Exercise Testing by John Resig, on Flickr"><img src="http://farm7.static.flickr.com/6003/5985481938_ab834e3c42.jpg" width="500" height="351" alt="Khan Exercise Testing"></a></center></p>
<p>All of this information is collected and distilled into a piece of JavaScript code that is dropped into our <a href="https://github.com/Khan/khan-exercises/tree/master/test/exercises">test suite</a>, all pushed into QUnit. At the moment we have around 2414 unit test collections with over 10,000 assertions.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5984923703/" title="Khan Exercise Test Dump by John Resig, on Flickr"><img src="http://farm7.static.flickr.com/6017/5984923703_2496715189_m.jpg" width="240" height="215" alt="Khan Exercise Test Dump"></a></center></p>
<p>At the moment we're working on ways of having better reporting and integration with our development process, for all those unit tests.</p>
<h2>Development Process</h2>
<p>I'm rather pleased with how the overall development process worked out. We actively kept both the code open (it's up on Github and it's MIT licensed) and the process open as well. We've had contributions from over twice as many outside contributors than members of the Khan Academy team (although the vast majority of the development was done by members of the team).</p>
<p>We have a <a href="https://github.com/Khan/khan-exercises/wiki/Getting-Involved">detailed Getting Involved guide</a> that explains how exactly anyone can participate in the development of the framework (or in the authoring of new exercises).</p>
<p>Predominantly we've been coordinating through <a href="http://www.hipchat.com/g2m3UVDtY">a public HipChat room</a>, using the <a href="https://github.com/Khan/khan-exercises/issues">Github Issue Tracker</a>, and managing all the exercise work through a series of Google Spreadsheets.</p>
<p>We're going to be transitioning now into creating a ton more exercises and we'd love to have even more help from the community. There is a ton of information on <a href="https://github.com/Khan/khan-exercises/wiki/Getting-Involved">how to get involved</a> in the <a href="https://github.com/Khan/khan-exercises/wiki">wiki</a>.</p>
<h2>Next Steps and Thanks</h2>
<p>There are a few things that we're looking to do in the near future: Bring offline support to the exercises (for those with spotty internet connections or those using the upcoming iPad/Android application), client-side translation of content into other languages, and exercise answer checking using Node.js and JSDOM.</p>
<p>I also want to take this opportunity to thank everyone at Khan Academy, and all the community contributors, for helping to make this project happen. I especially want to thank Marcia Lee, Ben Alpert, Jeff Ruberg, Igor Terzic, Omar Rizwan, and Ben Kamens for their help in getting this out the door.</p>
<p>I should also mention that <a href="http://hire.jobvite.com/CompanyJobs/Careers.aspx?k=JobListing&#038;c=qd69Vfw7">Khan Academy is hiring devs</a>. We're looking for both server/client devs (Python/JavaScript) and also mobile devs (iOS and Android).</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/ogLAcLijUBw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/khan-exercise-rewrite/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Random Khan Exercises</title>
		<link>http://ejohn.org/blog/random-khan-exercises/</link>
		<comments>http://ejohn.org/blog/random-khan-exercises/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 19:06:34 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5771</guid>
		<description><![CDATA[We're taking an innovative new approach to providing students with exercises in the new Khan Academy exercise framework (which will be released for beta testing soon). In the old framework a problem would be randomly generated and provided to the user. This would result in a near-infinite number of randomly generated problems. This ends up [...]]]></description>
			<content:encoded><![CDATA[<p>We're taking an innovative new approach to providing students with exercises in the <a href="http://github.com/khan/khan-exercises">new Khan Academy exercise framework</a> (which will be released for beta testing soon). In the old framework a problem would be randomly generated and provided to the user. This would result in a near-infinite number of randomly generated problems.</p>
<p>This ends up being a double-edged sword. While it's great to provide a ton of problem variety to the students it's fundamentally tricky as we want to have a manageable sample size of problems so that we can analyze student behavior and responses. For this reason we want to reduce the pool of possible problems to a more-manageable size (like about 200 or so - we'll experiment with exact figures as time goes by). Most students will only do about 10-20 problems before moving on (since we define a 'streak' as having completed 10 problems in a row correctly) - although we want to provide enough of a pool to allow adventurous users to explore more.</p>
<p>Having a smaller pool size creates another issue though: Potential for student overlap. If there's one thing that we've learned so far it's that students are quite resourceful and identify patterns very quickly. They will realize if they start on the same problem together and if the problems go in the same order.</p>
<p>On top of this we need to make it so that every time the student hits the exercise they are presented with the same exact series of exercises. The first problem will always be the same - and the 50th problem will always be the same for that user. (This will allow us to reproduce the problems at a later date, showing them their problems/answers or analyzing the results.)</p>
<p>Thus we need two pieces of information to determine which problem should be presented to a user: The user's ID and the problem # that they're currently tackling.</p>
<p>We start by placing the user into a simple "bin": We take the <a href="http://en.wikipedia.org/wiki/Cyclic_redundancy_check">CRC32</a> of the student's ID and mod 200 to start the user at one of the 200 possible exercises. (We picked CRC32 as it's a simple function and we only need a basic level of granularity in the results.) Next we use the CRC32 to figure out how the user should jump through the exercises.</p>
<p>We can't jump through the exercises 1 by 1, since the students will instantly recognize that pattern, so we have to take a random approach - one developed by Khan Academy intern <a href="https://plus.google.com/101013822660106280579/posts">Ben Alpert</a>.</p>
<p>We start with a pool of prime numbers (the first 23 primes, to be exact) and use the user's CRC32 to determine which of those primes will become the "jump distance" for that user.</p>
<p>For example:</p>
<div class="syntax_hilite">
<div id="js-6">
<div><span style="color: #003366; font-weight: bold;">var</span> primes = <span style="color:#008800; font-weight:bold;">&#91;</span><span style="color: #CC0000;">3</span>, <span style="color: #CC0000;">7</span>, <span style="color: #CC0000;">11</span>, <span style="color: #CC0000;">13</span>, <span style="color: #CC0000;">17</span>, <span style="color: #CC0000;">19</span>, <span style="color: #CC0000;">23</span>, <span style="color: #CC0000;">29</span>, <span style="color: #CC0000;">31</span>, <span style="color: #CC0000;">37</span>, <span style="color: #CC0000;">41</span>, <span style="color: #CC0000;">43</span>,<br />
&nbsp; <span style="color: #CC0000;">47</span>, <span style="color: #CC0000;">53</span>, <span style="color: #CC0000;">59</span>, <span style="color: #CC0000;">61</span>, <span style="color: #CC0000;">67</span>, <span style="color: #CC0000;">71</span>, <span style="color: #CC0000;">73</span>, <span style="color: #CC0000;">79</span>, <span style="color: #CC0000;">83</span>, <span style="color: #CC0000;">89</span>, <span style="color: #CC0000;">97</span><span style="color:#008800; font-weight:bold;">&#93;</span>;</p>
<p><span style="color: #003366; font-weight: bold;">var</span> num = crc32<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"jeresig"</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
<span style="color: #009900; font-style: italic;">// num = 1411847358</span></p>
<p><span style="color: #003366; font-weight: bold;">var</span> problemNum = num % <span style="color: #CC0000;">200</span>;<br />
<span style="color: #009900; font-style: italic;">// problemNum = 158</span></p>
<p><span style="color: #003366; font-weight: bold;">var</span> jumpNum = primes<span style="color:#008800; font-weight:bold;">&#91;</span> num % primes.<span style="color: #006600;">length</span> <span style="color:#008800; font-weight:bold;">&#93;</span>;<br />
<span style="color: #009900; font-style: italic;">// jumpNum = 71 </span><br />
&nbsp;</div>
</div>
</div>
<p>Thus when I visit a particular problem I will start at problem # 158, then go to problem 29, then problem 100, then problem 171, etc. On the other hand, if user "jeresig2" visits the same problem they start at problem 171 then visit problem 182, 193, 4, etc.</p>
<p>(Note that we leave out 2 and 5 to avoid creating a circular loop of exercises - 2 will result in 100 repeating exercises, 5 will result in 40 repeating exercises. Of course we could just make the number of exercises prime to achieve a similar result - we'll see!)</p>
<p>Even though we're not using any built-in random number generator in this process, the distribution of chosen problems appears to be similar to a random distribution (since we've effectively implemented one ourselves):</p>
<p><a href="http://www.flickr.com/photos/jeresig/5954863467/" title="Khan Problem Probability Distribution by John Resig, on Flickr"><img src="http://farm7.static.flickr.com/6017/5954863467_4b415bd2fc_b.jpg" width="674" height="264" alt="Khan Problem Probability Distribution"></a></p>
<p>To re-emphasize: We're not trying to stop problem overlap - in fact we want overlap to occur, to give us data to study - but a lack of repeatable patterns has definitely been arrived at here.</p>
<p>We chose a collection of 23 primes because it is sufficiently large - but it also doesn't divide into 200 cleanly (giving users that might have an identical starting position a different jump amount).</p>
<p>Also note that in the final solution we're going to be combining the user's ID with the name of the current problem - so that even if, somehow, two students end up with identical start positions and jump rates on one exercise they will have a different start position and jump rate on other exercises.</p>
<p>If all goes well we'll be opening up the new exercise rewrite for beta testing within the next week or two.</p>
<blockquote><p><strong>Note:</strong> I've been posting interesting dev updates over <a href="https://plus.google.com/115675748062237570841/posts">on Google Plus</a>. Feel free to follow me there if you wish to find out more about what I'm working on with Khan Academy or jQuery.</p></blockquote>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/h6wWpeK7Q1Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/random-khan-exercises/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>jQuery 1.6 and .attr()</title>
		<link>http://ejohn.org/blog/jquery-16-and-attr/</link>
		<comments>http://ejohn.org/blog/jquery-16-and-attr/#comments</comments>
		<pubDate>Fri, 13 May 2011 14:04:47 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5766</guid>
		<description><![CDATA[jQuery 1.6 and 1.6.1 are out the door. Congrats to the team and everyone that was involved with the release! A relatively controversial change in 1.6 was regarding how attributes and DOM object properties were handled. In 1.6 we wanted to take the major step of completely separating the two, allowing us to create an [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://blog.jquery.com/2011/05/03/jquery-16-released/">jQuery 1.6</a> and <a href="http://blog.jquery.com/2011/05/12/jquery-1-6-1-released/">1.6.1</a> are out the door. Congrats to the team and everyone that was involved with the release!</p>
<p>A relatively controversial change in 1.6 was regarding how attributes and DOM object properties were handled. In 1.6 we wanted to take the major step of completely separating the two, allowing us to create an <code>.attr()</code> method that wasn't quite so mealy-mouthed with regards to how attributes were handled. We did this in 1.6 because we felt that it was a substantial change (we only do major changes in the 1.x major releases of jQuery) and had the possibility of affecting people.</p>
<p>We did a considerable amount of testing on the code and we were quite confident that the amount of problems that people would encounter, while upgrading, would be quite minimal. The biggest pain points, we surmised, would be regarding how boolean attributes were handled (attributes like "disabled" or "selected"). However most of this would be mitigated and would likely have worked fine for users that consistently used <code>.attr()</code> to access and update their attributes.</p>
<p>After making the changes, and publishing 1.6, there were enough complaints that we had changed the API to cause us to reconsider and return <code>.attr()</code> to its sometimes-attribute, sometimes-property, state.</p>
<p>jQuery is in an incredibly tricky position now (and has been for some time). We very rarely add features to the library, for fear of bloat and added API maintenance overhead, and are rarely able to make any sort of API change, for fear of preventing people from upgrading.</p>
<p>Thankfully even though we've reverted some of the changes in 1.6, we've done it in a way that still maintains the performance gains that we achieved with the 1.6 release.</p>
<p>I wanted to try and <a href="https://github.com/jquery/jquery/blob/master/src/attributes.js#L293">summarize the <code>.attr()</code> method</a>, to explain how it currently works in 1.6.1, but ended up writing up a sample function instead (note that this is a bit of an over-simplification, please <a href="https://github.com/jquery/jquery/blob/master/src/attributes.js#L293">read the code</a> for more details):</p>
<div class="syntax_hilite">
<div id="js-10">
<div><span style="color: #003366; font-weight: bold;">function</span> attr<span style="color:#008800; font-weight:bold;">&#40;</span> elem, <span style="color: #000066;">name</span>, value <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Are we setting a value?</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> value !== undefined <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Make sure the element has the ability to set an attribute</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #000066; font-weight: bold;">typeof</span> elem.<span style="color: #006600;">setAttribute</span> !== <span style="color: #3366CC;">"undefined"</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If the user is setting the value to false</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> value === <span style="color: #003366; font-weight: bold;">false</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Completely remove the attribute</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; elem.<span style="color: #006600;">removeAttribute</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #000066;">name</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Otherwise set the attribute value</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If the user is setting the value to true,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Set it equal to the name of the attribute</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// (handles boolean attributes nicely)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; elem.<span style="color: #006600;">setAttribute</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #000066;">name</span>, value === <span style="color: #003366; font-weight: bold;">true</span> ? <span style="color: #000066;">name</span> : value <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If it doesn't, then we're likely dealing with window or document</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// (or some other object entirely)</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; elem<span style="color:#008800; font-weight:bold;">&#91;</span> <span style="color: #000066;">name</span> <span style="color:#008800; font-weight:bold;">&#93;</span> = value;<br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// Otherwise we're getting an attribute value</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Check to see if the appropriate method exists</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Also don't use getAttribute if a boolean property exists</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #000066; font-weight: bold;">typeof</span> elem.<span style="color: #006600;">getAttribute</span> !== <span style="color: #3366CC;">"undefined"</span> &amp;&amp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">typeof</span> elem<span style="color:#008800; font-weight:bold;">&#91;</span> <span style="color: #000066;">name</span> <span style="color:#008800; font-weight:bold;">&#93;</span> !== <span style="color: #3366CC;">"boolean"</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> elem.<span style="color: #006600;">getAttribute</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #000066;">name</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// If no getAttribute method is present, or if we</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// wish to access the boolean property instead of the</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// attribute, then we fallback to the DOM object property</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> elem<span style="color:#008800; font-weight:bold;">&#91;</span> <span style="color: #000066;">name</span> <span style="color:#008800; font-weight:bold;">&#93;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>Ironically this isn't much shorter than the <a href="https://github.com/jquery/jquery/blob/master/src/attributes.js#L293">actual <code>.attr()</code> implementation</a>, I recommend that you check it out.</p>
<p>There's a very good chance that your code, written targeting 1.5.2, will continue to work just fine in 1.6.1 using this particular technique.</p>
<p>However this point now begs the question: <strong>Why does .prop() exist?</strong></p>
<p>In short, for two reasons:</p>
<ol>
<li>There are legitimate use cases for interacting with some DOM properties (such as <code>nodeName</code>, <code>selectedIndex</code>, or <code>defaultValue</code>) and we want to provide a simple solution for accessing, and mutating, them.</li>
<li>Accessing properties through the <code>.attr()</code> method will be slightly slower than accessing them directly through <code>.prop()</code> (as <code>.attr()</code> calls <code>.prop()</code> internally in order to handle all property-related mutation).</li>
</ol>
<p>In jQuery 1.5.2, and older, in order to access a DOM property you would have to do something like this:</p>
<div class="syntax_hilite">
<div id="js-11">
<div><span style="color: #003366; font-weight: bold;">var</span> elem = $<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"#foo"</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#91;</span><span style="color: #CC0000;">0</span><span style="color:#008800; font-weight:bold;">&#93;</span>;<br />
<span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> elem <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; index = elem.<span style="color: #006600;">selectedIndex</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>In 1.6+ you can just do:</p>
<div class="syntax_hilite">
<div id="js-12">
<div>index = $<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"#foo"</span><span style="color:#008800; font-weight:bold;">&#41;</span>.<span style="color: #006600;">prop</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"selectedIndex"</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p>Summary: There's a good chance that your code won't be affected at all with the changes that've happened, especially so with the changes in 1.6.1, and jQuery now has a convenience method for handling DOM properties in a simpler, and slightly faster, manner.</p>
<p>Tangentially this reminds me of a common question that I hear: <strong>What will be in jQuery 2.0?</strong> I have no idea what will be in that release, should it ever arrive, but I do know what <em>won't</em> be in it: A massive API change of any sort. Even when we make, relatively minor, API changes like in the 1.6 release the amount of negative feedback that we get is monumental. If we've learned anything after doing <a href="http://docs.jquery.com/Downloading_jQuery">31 releases</a> of jQuery it's that people like having stability in their API and will cherish that over everything else.</p>
<p>I do want to thank the community though for being so vocal and working to communicate with the team so actively. Without the community's communication and support it's doubtful that the team would be able to continue operating.</p>
<p>I would like to take this opportunity to encourage everyone to <a href="http://docs.jquery.com/Getting_Involved">get involved</a> with the development of jQuery. We hold active discussions every day in IRC and hold public meetings once a week. We also post <a href="http://jquery.org/updates/category/core/">weekly status updates</a> if you wish to follow along. Right now we're working on the 1.7 release of the library and are actively encouraging contributions and feedback. If you want to help ensure the quality and stability of the next release of jQuery, the best way to do so is to get involved. Hope to see you around the bug tracker.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/9ATQ-8y6Lyo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/jquery-16-and-attr/feed/</wfw:commentRss>
		<slash:comments>41</slash:comments>
		</item>
		<item>
		<title>Next Steps in 2011</title>
		<link>http://ejohn.org/blog/next-steps-in-2011/</link>
		<comments>http://ejohn.org/blog/next-steps-in-2011/#comments</comments>
		<pubDate>Tue, 03 May 2011 16:17:32 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5755</guid>
		<description><![CDATA[Today I'm announcing a major change in my life: I'm leaving Mozilla Corporation and joining Khan Academy. I joined the Mozilla Corporation in January of 2007, just over 4+ years ago, as a JavaScript Evangelist. During my time at the company I had an amazing opportunity to promote JavaScript. It's been an incredible experience working [...]]]></description>
			<content:encoded><![CDATA[<p>Today I'm announcing a major change in my life: I'm leaving Mozilla Corporation and joining <a href="http://www.khanacademy.org/">Khan Academy</a>.</p>
<p><img src="http://upload.wikimedia.org/wikipedia/en/thumb/4/49/Mozilla_Mascot.svg/200px-Mozilla_Mascot.svg.png" style="float: right; margin: 0 0 10px 10px;"/></p>
<p>I joined the Mozilla Corporation in January of 2007, just over 4+ years ago, as a JavaScript Evangelist. During my time at the company I had an amazing opportunity to promote JavaScript. It's been an incredible experience working with everyone at Mozilla. The company is easily one of the most developer-friendly organizations I can imagine, with some of the smartest coders in the world. Mozilla is <a href="http://www.mozilla.com/en-US/careers/">hiring across the board</a> - I strongly encourage you to apply if you're looking for one of the best jobs you've ever had.</p>
<p>I had the opportunity to promote JavaScript as a JavaScript Evangelist (and build tools like <a href="https://wiki.mozilla.org/FUEL">FUEL</a>, <a href="http://dromaeo.com/">Dromaeo</a>, and <a href="http://processingjs.org/">Processing.js</a>) and work as a JavaScript Tool Developer (building tools like <a href="http://swarm.jquery.org/">TestSwarm</a>, <a href="http://fireunit.org/">FireUnit</a>, and improving <a href="http://docs.jquery.com/Qunit">QUnit</a>).</p>
<p>Over the past year and a half Mozilla gave me the ability to work on jQuery full-time. This has resulted in 9 releases of jQuery (including today's release of <a href="http://blog.jquery.com/2011/05/03/jquery-16-released/">jQuery 1.6</a>) and a drastically improved jQuery organization (we're now under the <a href="http://sfconservancy.org/">Software Freedom Conservancy</a> non-profit, hold frequent team meetings, <a href="http://groups.google.com/group/jquery-team-public">public votes</a>, provide <a href="http://jquery.org/updates/">public status updates</a>, and <a href="http://docs.jquery.com/Getting_Involved">actively encourage participation</a>). Thankfully the jQuery project is running quite smoothly these days, allowing me to scale back my involvement to a more-reasonable amount of time and take on other development work.</p>
<p><img src="http://www.khanacademy.org/images/khan-logo-vertical-transparent.png" style="float: right; margin: 0 0 10px 10px;"/></p>
<p>Lately I've been looking for a chance to get back into active application development again. I've been working on a few applications in my spare time (mostly mobile-centric applications, using jQuery Mobile) and an excellent opportunity has arrived.</p>
<p>Starting next Monday I will be working at <a href="http://www.khanacademy.org/">Khan Academy</a> full-time leading their Open Source efforts and JavaScript development. If you aren't familiar with Khan Academy I highly recommend watching <a href="http://www.ted.com/talks/salman_khan_let_s_use_video_to_reinvent_education.html">the excellent talk at Ted</a> given by Sal Khan himself. In short: Khan Academy is attempting to revolutionize how students learn and how teachers are able to help students.</p>
<p>Learning, and teaching others, has been a life-long passion for me. I see Khan Academy as a fantastic realm in which I can help to promote education and work to design better tools for teaching and getting people involved with Open Source. More than anything else I want to increase the size and activity of the community around Khan Academy. This includes everything from getting more casual contributors (such as those writing problems sets) to getting more code and debugging contributions.</p>
<p>When I start I'm going to be working on rewriting the framework for creating problem sets, constructing the initial version of the iPad application, and working to improve Khan Academy's Open Source efforts.</p>
<p>It's incredibly important to me that Khan Academy is a non-profit and is working to ensure that all generated material (videos, exercises, and even the application itself) will be released for free and in the open. I'm going to be working to ensure that this continues into the future with help from contributors in the community.</p>
<p>Khan Academy is very excited to have me continue working on jQuery during my day-to-day along with continuing to speak at conferences. Additionally I will be continuing to live in Boston for the foreseeable future.</p>
<blockquote><p>I should note that I've made a personal decision to scale back some other aspects of my professional life. I'm no longer accepting any new speaking engagements. For the rest of this year I will only be speaking at Velocity in June, the jQuery Conference in October, and Fronteers in October.</p>
<p>Additionally a new co-author, Bear Bibeault, has been brought on to help with the completion of my book: <a href="http://jsninja.com/">Secrets of the JavaScript Ninja</a>. With his help the book should be finalized this year.</p></blockquote>
<p>I'm terribly excited about this new opportunity and can hardly wait to begin. Thank you to Mozilla for the opportunity these past few years and thank you to Khan Academy for accepting me aboard. Here's to a wonderful 2011!</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/LBEl2mu59E0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/next-steps-in-2011/feed/</wfw:commentRss>
		<slash:comments>144</slash:comments>
		</item>
		<item>
		<title>Pulley: Easy Github Pull Request Landing</title>
		<link>http://ejohn.org/blog/pulley/</link>
		<comments>http://ejohn.org/blog/pulley/#comments</comments>
		<pubDate>Fri, 22 Apr 2011 03:04:31 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5748</guid>
		<description><![CDATA[I've created a simple tool for landing pull requests from Github, which I'm calling "Pulley". Landing a pull request from Github can be annoying. You can follow the instructions provided by Github (pulling the code, doing a merge) but that'll result in a messy commit stream and external ticket trackers that don't automatically close tickets. [...]]]></description>
			<content:encoded><![CDATA[<p>I've created a simple tool for landing pull requests from Github, which I'm calling "<a href="https://github.com/jeresig/pulley">Pulley</a>".</p>
<p>Landing a pull request from Github can be annoying. You can follow the instructions provided by Github (pulling the code, doing a merge) but that'll result in a messy commit stream and external ticket trackers that don't automatically close tickets. The series of commands that you run will typically look something like this:</p>
<pre>git checkout -b branchname master
git pull http://url/to/otherrepo branchname
git checkout master
git merge branchname
git push origin master</pre>
<p>Additionally you can pull the code and squash it down into a single commit, which lets you format the commit nicely (closing tickets on external trackers) - but it fails to properly close the pull request. The commands for which look something like this:</p>
<pre>git checkout master
git checkout -b bug1234
git pull http://url/to/otherrepo branchname
git checkout master
git merge --no-commit --squash bug1234
git commit -a --author="Original Author <author@email.example>"

# To get the author:
git log | grep "Author" | head -1</pre>
<p>Pulley is a tool that uses the best aspects of both techniques. Pull requests are pulled and merged into your project. The code is then squashed down into a single commit and nicely formatted with appropriate bug numbers and links. Finally the commit is pushed and the pull request is closed with a link to the commit.</p>
<p>Pulley is written using Node.js - thus you'll need to make sure that you have Node installed prior to running it.</p>
<p><strong>How to use:</strong></p>
<p>Download <a href="https://github.com/jeresig/pulley">a copy of Pulley</a> or install it via <a href="http://npmjs.org/">npm</a>: <code>npm install pulley</code> and configure the repo and bug tracker details in the pulley.js file (this is only necessary if you use a custom, non-Github, issue tracker).</p>
<p>You'll also need to set up your Github username and token into your Git repo. More details can be found <a href="http://help.github.com/git-email-settings/">in the Github docs</a>.</p>
<p>Once that's complete you can run the following command:</p>
<pre>node pulley.js PID # Where PID is the Pull Request ID</pre>
<p>For example running the command <code>node pulley.js 332</code> on the jQuery repo yielded the following closed pull request, commit, and tickets:</p>
<p><center><a href="https://github.com/jquery/jquery/pull/332"><img src="http://gyazo.com/95b2e65d92aaff88b96dae0247767866.png"/></a></center></p>
<p><center><a href="https://github.com/jquery/jquery/commit/d274b7b9f7727e8bccd6906d954e4dc790404d23"><img src="http://gyazo.com/8e0737911359954f0027afbe0758f286.png"/></a></center></p>
<p><center><a href="http://bugs.jquery.com/ticket/8500"><img src="http://gyazo.com/6f5a1a506d15aa63b1698a6fda625e83.png"/></a></center></p>
<p>The configuration is still a bit janky but it works well enough for me - I'm looking forward to landing a few pull requests to improve it.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/8JvTpmJwzUQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/pulley/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Revised JavaScript Dictionary Search</title>
		<link>http://ejohn.org/blog/revised-javascript-dictionary-search/</link>
		<comments>http://ejohn.org/blog/revised-javascript-dictionary-search/#comments</comments>
		<pubDate>Tue, 22 Mar 2011 23:52:58 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5744</guid>
		<description><![CDATA[After my two previous posts discussing dictionary lookups in JavaScript and JavaScript Trie performance analysis even more excellent feedback came in from everyone. Out of all the results two techniques seemed to be most interesting - and promising for reducing general memory usage and load time. String-based Binary Search The first technique proposed was left [...]]]></description>
			<content:encoded><![CDATA[<p>After my two previous posts discussing <a href="http://ejohn.org/blog/dictionary-lookups-in-javascript/">dictionary lookups in JavaScript</a> and <a href="http://ejohn.org/blog/javascript-trie-performance-analysis/">JavaScript Trie performance analysis</a> even more excellent feedback came in from everyone.</p>
<p>Out of all the results two techniques seemed to be most interesting - and promising for reducing general memory usage and load time.</p>
<h2>String-based Binary Search</h2>
<p>The first technique proposed was <a href="http://ejohn.org/blog/javascript-trie-performance-analysis/#comment-392158">left as a comment</a> by a commenter named Randall. He utilized a technique <a href="http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392072">posited by Mathias Nater</a> to create a smaller dictionary and search the results using a <a href="http://en.wikipedia.org/wiki/Binary_search_algorithm">binary search</a>.</p>
<p>The technique breaks down into two parts: The smaller dictionary and the binary search.</p>
<p>The smaller dictionary is achieved by taking the regular dictionary and grouping the words by length. Thus you'll end up with clusters of words that are all equal lengths. For example:</p>
<div class="syntax_hilite">
<div id="js-15">
<div><span style="color:#008800; font-weight:bold;">&#91;</span><br />
&nbsp; <span style="color: #3366CC;">"catdoghat"</span>,&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// all length 3</span><br />
&nbsp; <span style="color: #3366CC;">"foodridewood"</span>, <span style="color: #009900; font-style: italic;">// all length 4</span><br />
&nbsp; ... <span style="color: #006600;">etc</span>.<br />
<span style="color:#008800; font-weight:bold;">&#93;</span></div>
</div>
</div>
<p>If all the words in a particular string are the same length then it makes it quite easy to jump around inside it (you just always move forwards or backwards in the string one word's length). This reduces the resulting, uncompressed, file size of the dictionary by about 110,000 bytes (there is now one less space for each word in the dictionary).</p>
<p>Having the words of uniform length makes it easy to implement a binary search. The code written by Randall is rather simple and effective:</p>
<div class="syntax_hilite">
<div id="js-16">
<div><span style="color: #003366; font-weight: bold;">function</span> findBinaryWord<span style="color:#008800; font-weight:bold;">&#40;</span> word <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Figure out which bin we're going to search</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> l = word.<span style="color: #006600;">length</span>;<br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// Don't search if there's nothing to look through</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> !dict<span style="color:#008800; font-weight:bold;">&#91;</span>l<span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// Get the number of words in the dictionary bin</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> words = dict<span style="color:#008800; font-weight:bold;">&#91;</span>l<span style="color:#008800; font-weight:bold;">&#93;</span>.<span style="color: #006600;">length</span> / l,<br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// The low point from where we're starting the binary search</span><br />
&nbsp; &nbsp; low = <span style="color: #CC0000;">0</span>,<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// The max high point</span><br />
&nbsp; &nbsp; high = words - <span style="color: #CC0000;">1</span>,<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// And the precise middle of the search</span><br />
&nbsp; &nbsp; mid = Math.<span style="color: #006600;">floor</span><span style="color:#008800; font-weight:bold;">&#40;</span> words / <span style="color: #CC0000;">2</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// We continue to look until we reach a final word</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">while</span> <span style="color:#008800; font-weight:bold;">&#40;</span> high &gt;= low <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Grab the word at our current position</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> found = dict<span style="color:#008800; font-weight:bold;">&#91;</span>l<span style="color:#008800; font-weight:bold;">&#93;</span>.<span style="color: #006600;">substr</span><span style="color:#008800; font-weight:bold;">&#40;</span> l * mid, l <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If we've found the word, stop now</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> word === found <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">true</span>;<br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Otherwise, compare</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If we're too high, move lower</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> word &lt; found <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; high = mid - <span style="color: #CC0000;">1</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If we're too low, go higher</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; low = mid + <span style="color: #CC0000;">1</span>;<br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// And find the new search point</span><br />
&nbsp; &nbsp; mid = Math.<span style="color: #006600;">floor</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color:#008800; font-weight:bold;">&#40;</span>low + high<span style="color:#008800; font-weight:bold;">&#41;</span> / <span style="color: #CC0000;">2</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// Nothing was found</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>Doing a binary search will almost certainly yield a faster result compared to a simple linear search through the string (such as doing a <code>.indexOf</code>).</p>
<h2>Trie Stored in a Succinct Data Structure</h2>
<p>The other solution that popped up was proposed by <a href="http://stevehanov.ca/blog/index.php?id=120">Steve Hanov</a>. His solution was to continue utilizing the Trie structure but store it in a <em>succinct data structure</em>. He explains it extremely well so I would highly recommend visiting his blog to get the full details of the solution.</p>
<p>In short all the leaves of the Trie are given a number and stored in a table (resulting in a data structure for lookups and a data structure for the actual data itself). Additionally he went a step further and encoded all the data using Base 64 and modified the algorithm to utilize that encoding - thus all the encoded data can remain as a string and never have to be turned into a large JavaScript data structure.</p>
<p>Ideally this solution will provide a much smaller file size and memory usage.</p>
<h2>File Size Analysis</h2>
<p>We still want to make sure that the file size of the dictionary isn't too large - saving us some potential bandwidth costs. Digging in to the file size results yields some very interesting data.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5550985855/" title="Revised Dictionary File Size by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5143/5550985855_67d5510893.jpg" width="500" height="375" alt="Revised Dictionary File Size" /></a></center></p>
<p>Unsurprisingly the uncompressed binary string is smaller than the plain string - but quite surprisingly the final gzipped size actually ends up being larger than the original. I can only assume that the spacing in the original ended up helping the gzip algorithm compress the resulting text easier - definitely not an intuitive result, though.</p>
<p>Additionally when we look at the results for the succinct Trie we do see that it's uncompressed file size is quite small (only about 300KB). Amusingly, its compressed file size ends up being larger than any of the previous Trie structures - but still smaller than the regular strings.</p>
<p>If we were only concerned with file size then the suffix optimized Trie would still be the way to go.</p>
<h2>Load Speed Analysis</h2>
<p>As with before, analyzing the initial load speed of the dictionary ends up being crucial. If we're utilizing a JavaScript object we have to evaluate it first - and that can end up taking a considerable amount of time.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5551571616/" title="Revised Dictionary Load Speed by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5138/5551571616_bddb21cf13.jpg" width="500" height="375" alt="Revised Dictionary Load Speed" /></a></center></p>
<p>Thankfully both of the new techniques load virtually instantaneously (taking only 0.65 - 1.7ms to load the whole dictionary, which makes sense, since they're both coming from simple strings and require no code evaluation).</p>
<h2>Search Speed Analysis</h2>
<p>As I mentioned in my last post, the performance of word lookups wasn't nearly as important in my particular use case as all the other considerations. Having a lookup take a couple milliseconds was OK since they were only going to occur every couple seconds or so. This may not be the case for every application - and I still wanted to make sure that the code wasn't going to take any major performance hits.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5551570608/" title="Revised Dictionary Search Speed by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5173/5551570608_b1caacc03d.jpg" width="500" height="375" alt="Revised Dictionary Search Speed" /></a></center></p>
<p>The binary string search ends up being quite fast - even faster than the old Trie search, which is quite promising. However the new Succinct Trie ends up being disturbingly slow (taking about 5.5ms to look up a word in Node.js on a fast machine). I double-checked and the lookup time for finding a word on an iPhone 4 using iOS 4.3 is about 46ms. Even taking that into account I think that's still a lookup rate that I can live with in my particular application. However it most certainly will be too slow for many situations (and in those cases they'll likely want to use the Binary String technique).</p>
<p>It's not clear to me how much of the Succinct Trie's performance stems from its implementation. Perhaps there could be some improvements made to it to increase its final word search time.</p>
<h2>Memory Usage Analysis</h2>
<p>I finally revisited memory usage, as well. This continues to be critical on mobile devices. Using too much memory will cause all sorts of problems and frequently force the browser to reload your application.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5551570028/" title="Revised Dictionary Memory Usage by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5181/5551570028_478fa70071.jpg" width="500" height="375" alt="Revised Dictionary Memory Usage" /></a></center></p>
<p>The Binary String technique does well. Being a simple string (and of a smaller total size) means that it uses less memory as well. However the Succinct Trie technique does absolutely stellar - as it's a string as well, and since it's total uncompressed size is only about 1/3 of a MB, that's all the memory that it ends up using. This is fantastic and certainly a huge encouragement towards using this technique.</p>
<h2>Conclusion</h2>
<p>Even though it's not quite as small (compressed file-size-wise) as a regular Trie and even though its lookup speed is significantly slower than any other technique (but still usable) - I'm heavily inclined to use the <a href="http://stevehanov.ca/blog/index.php?id=120">Succinctly Stored Trie Structure</a>. I would definitely like to encourage everyone to look at this particular technique further as, currently, it provides excellent memory usage, reasonably-small file size, and virtually non-existent startup overhead. If you're OK with having relatively slow word lookups then this is certainly the technique for you.</p>
<p>If slow lookup speed is undesirable then I would be inclined to use the binary string search technique (as it still provides decent memory usage, reasonable file size, and reasonable memory usage).</p>
<p>As always, all the code and tests are up on Github:<br />
<strong><a href="https://github.com/jeresig/trie-js">https://github.com/jeresig/trie-js</a></strong></p>
<h3>Raw Data</h3>
<p>The raw data for the updated tests (which can be found <a href="https://github.com/jeresig/trie-js">in my Trie.js Github repo</a>) are as follows:</p>
<p><small>
<pre>Binary String
--------------
Normal: 806KB
Gzipped: 326KB
Build Speed: 174 (1.74ms per)
Find Speed: 369 (0.0033ms per)
Not Find Speed: 197 (0.0012ms per)
Private Memory: 112.2MB (0.98MB per)

Succinct Trie
--------------
Normal: 317KB
Gzipped: 197KB
Build Speed: 65 (0.65ms per)
Find Speed: 609985 (5.43ms per)
Not Find Speed: 622700 (5.54ms per)
Private Memory: 47.1MB (0.33MB per)</pre>
<p></small></p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/_1NAsABZvT4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/revised-javascript-dictionary-search/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>JavaScript Trie Performance Analysis</title>
		<link>http://ejohn.org/blog/javascript-trie-performance-analysis/</link>
		<comments>http://ejohn.org/blog/javascript-trie-performance-analysis/#comments</comments>
		<pubDate>Thu, 17 Mar 2011 14:48:03 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5733</guid>
		<description><![CDATA[After my last post discussing dictionary lookups in JavaScript the unanimous consensus seemed to be that utilizing Trie would result in additional space savings and yield performance benefits. A Trie is a relatively simple data structure. At its simplest form you're building a tree-like structure where each final leaf results in a complete word. This [...]]]></description>
			<content:encoded><![CDATA[<p>After my last post discussing <a href="http://ejohn.org/blog/dictionary-lookups-in-javascript/">dictionary lookups in JavaScript</a> the unanimous consensus seemed to be that utilizing <a href="http://en.wikipedia.org/wiki/Trie">Trie</a> would result in additional space savings and yield performance benefits.</p>
<p>A Trie is a relatively simple data structure. At its simplest form you're building a tree-like structure where each final leaf results in a complete word. This allows for some very efficient use of file size - reducing common prefixes in words quite easily.</p>
<p><center><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Trie_example.svg/200px-Trie_example.svg.png"/></center></p>
<p>I looked through a number of JavaScript Trie solutions and yet was not terribly pleased with them. They were either total overkill (including large object structures and functionality far beyond what I needed) or weren't compressing the resulting data structure enough. The closest in functionality that I found, to what I wanted, was what was <a href="http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392043">written by Henrik Hinrichs</a>, called <a href="https://github.com/mutaphysis/wordlistparser">wordlistparser</a>. Wordlistparser creates a simple Trie structure using Node.js.</p>
<p>I've dumped my work-in-progress <strong><a href="https://github.com/jeresig/trie-js">JavaScript Trie Generator</a></strong> up on Github (note that it requires Node.js to run).</p>
<p><strong>Generating a Trie</strong></p>
<p>The basic Trie generation functionality is as follows (note that I use '0' or '$:0' to indicate a complete word):</p>
<div class="syntax_hilite">
<div id="js-23">
<div><span style="color: #009900; font-style: italic;">// Go through all the words in the dictionary</span><br />
<span style="color: #000066; font-weight: bold;">for</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #003366; font-weight: bold;">var</span> i = <span style="color: #CC0000;">0</span>, l = words.<span style="color: #006600;">length</span>; i &lt; l; i++ <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Get all the letters that we need</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> word = words<span style="color:#008800; font-weight:bold;">&#91;</span>i<span style="color:#008800; font-weight:bold;">&#93;</span>, letters = word.<span style="color: #006600;">split</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">""</span><span style="color:#008800; font-weight:bold;">&#41;</span>, cur = trie;</p>
<p>&nbsp; <span style="color: #009900; font-style: italic;">// Loop through the letters</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #003366; font-weight: bold;">var</span> j = <span style="color: #CC0000;">0</span>; j &lt; letters.<span style="color: #006600;">length</span>; j++ <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> letter = letters<span style="color:#008800; font-weight:bold;">&#91;</span>j<span style="color:#008800; font-weight:bold;">&#93;</span>, pos = cur<span style="color:#008800; font-weight:bold;">&#91;</span> letter <span style="color:#008800; font-weight:bold;">&#93;</span>;</p>
<p>&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If nothing exists for this letter, create a leaf</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> pos == <span style="color: #003366; font-weight: bold;">null</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If it's the end of the word, set a 0,</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// otherwise make an object so we can continue</span><br />
&nbsp; &nbsp; &nbsp; cur = cur<span style="color:#008800; font-weight:bold;">&#91;</span> letter <span style="color:#008800; font-weight:bold;">&#93;</span> = j === letters.<span style="color: #006600;">length</span> - <span style="color: #CC0000;">1</span> ? <span style="color: #CC0000;">0</span> : <span style="color:#008800; font-weight:bold;">&#123;</span><span style="color:#008800; font-weight:bold;">&#125;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If a final leaf already exists we need to turn it</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// into an object to continue traversing</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> pos === <span style="color: #CC0000;">0</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; cur = cur<span style="color:#008800; font-weight:bold;">&#91;</span> letter <span style="color:#008800; font-weight:bold;">&#93;</span> = <span style="color:#008800; font-weight:bold;">&#123;</span> $: <span style="color: #CC0000;">0</span> <span style="color:#008800; font-weight:bold;">&#125;</span>;</p>
<p>&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Otherwise there is nothing to be set, so continue on</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; cur = cur<span style="color:#008800; font-weight:bold;">&#91;</span> letter <span style="color:#008800; font-weight:bold;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p><strong>Optimizing the Structure</strong></p>
<p>While this is fine I wanted to go a step further. Rather than having single letters at every leaf of the tree I saw much room for optimization. <a href="http://ejohn.org/blog/dictionary-lookups-in-javascript/#comment-392044">Dave Ward posted</a> a sample tree structure which was rather similar to what was generated by Henrik's code (only Henrik's code used '$:1' instead of 'end:true' to save bytes). Looking at the resulting tree structure provided by Dave I was not terribly pleased with the resulting number of objects or code length.</p>
<p><strong>Code posted by Dave Ward</strong></p>
<div class="syntax_hilite">
<div id="js-24">
<div><span style="color: #003366; font-weight: bold;">var</span> trie = <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; b: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; a: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; r: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end: <span style="color: #003366; font-weight: bold;">true</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; s: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end: <span style="color: #003366; font-weight: bold;">true</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span>,<br />
&nbsp; &nbsp; f: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; o: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; o: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end: <span style="color: #003366; font-weight: bold;">true</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span>,<br />
&nbsp; &nbsp; r: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; a: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end: <span style="color: #003366; font-weight: bold;">true</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end: <span style="color: #003366; font-weight: bold;">true</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span>;</div>
</div>
</div>
<p>I saw that letters that only had a single child could be reduced into a single string. "r a t" could just become "rat". Additionally there was no need to have a bulky <code>{$:1}</code> structure just to denote the end of a word when you could just use the number 1 to indicate that as well.</p>
<p><strong>Possible Optimization</strong></p>
<div class="syntax_hilite">
<div id="js-25">
<div><span style="color: #003366; font-weight: bold;">var</span> trie = <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; bar: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; $: <span style="color: #CC0000;">1</span>,<br />
&nbsp; &nbsp; s: <span style="color: #CC0000;">1</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span>,<br />
&nbsp; foo: <span style="color: #CC0000;">1</span>,<br />
&nbsp; rat: <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; $: <span style="color: #CC0000;">1</span>,<br />
&nbsp; &nbsp; e: <span style="color: #CC0000;">1</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span>;</div>
</div>
</div>
<p>This change compresses the structure of the Trie down to its bare minimum - using only 3 object literals instead of the previous 12. Using the particular Trie structure makes lookups slightly more challenging (you need to look at the entire start of the word string, rather than just the first character) but it still seems to perform well enough.</p>
<p>The code for optimization:</p>
<div class="syntax_hilite">
<div id="js-26">
<div><span style="color: #009900; font-style: italic;">// Optimize a Trie structure</span><br />
<span style="color: #003366; font-weight: bold;">function</span> optimize<span style="color:#008800; font-weight:bold;">&#40;</span> cur <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> num = <span style="color: #CC0000;">0</span>;</p>
<p>&nbsp; <span style="color: #009900; font-style: italic;">// Go through all the leaves in this branch</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #003366; font-weight: bold;">var</span> node <span style="color: #000066; font-weight: bold;">in</span> cur <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If the leaf has children</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #000066; font-weight: bold;">typeof</span> cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span> === <span style="color: #3366CC;">"object"</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Continue the optimization even deeper</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> ret = optimize<span style="color:#008800; font-weight:bold;">&#40;</span> cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// The child leaf only had one child</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// and was &quot;compressed&quot; as a result</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> ret <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Thus remove the current leaf</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">delete</span> cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Remember the new name</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; node = node + ret.<span style="color: #006600;">name</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// And replace it with the revised one</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span> = ret.<span style="color: #006600;">value</span>;<br />
&nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Keep track of how many leaf nodes there are</span><br />
&nbsp; &nbsp; num++;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; <span style="color: #009900; font-style: italic;">// If only one leaf is present, compress it</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> num === <span style="color: #CC0000;">1</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color:#008800; font-weight:bold;">&#123;</span> <span style="color: #000066;">name</span>: node, value: cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#125;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>There's still room for some additional improvement, though. I looked at the changes proposed by the <a href="http://en.wikipedia.org/wiki/Directed_acyclic_word_graph">directed acyclic word graph</a> and realized that there was a minor tweak that could be made for improving file size even more: Reducing the number of common suffixes.</p>
<p>For example if you had the following words: sliced, slicer, slices, diced, dicer, dices - you would note that they have common endings (d, r, s) that could be reduced. I added another simple improvement to my Trie implementation that took this into account.</p>
<div class="syntax_hilite">
<div id="js-27">
<div><span style="color: #003366; font-weight: bold;">var</span> trie = <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; slice: <span style="color: #CC0000;">1</span>,<br />
&nbsp; dice: <span style="color: #CC0000;">1</span>,<br />
&nbsp; $: <span style="color:#008800; font-weight:bold;">&#91;</span> <span style="color: #CC0000;">0</span>, <span style="color:#008800; font-weight:bold;">&#123;</span> d: <span style="color: #CC0000;">0</span>, r: <span style="color: #CC0000;">0</span>, s: <span style="color: #CC0000;">0</span> <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color:#008800; font-weight:bold;">&#93;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span>;</div>
</div>
</div>
<p>While it's not as impressive with only two root words - it ends up working surprisingly well when you have over 100,000 words, reducing file size even more. The full code for finding, and reducing, the common suffixes can be found <a href="https://github.com/jeresig/trie-js/blob/master/build-trie.js#L70">on Github</a>.</p>
<p><strong>Finding a Word</strong></p>
<p>To find a word in the Trie it requires a little more work than the traditional Trie search:</p>
<div class="syntax_hilite">
<div id="js-28">
<div><span style="color: #003366; font-weight: bold;">function</span> findTrieWord<span style="color:#008800; font-weight:bold;">&#40;</span> word, cur <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Get the root to start from</span><br />
&nbsp; cur = cur || dict;<br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// Go through every leaf</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #003366; font-weight: bold;">var</span> node <span style="color: #000066; font-weight: bold;">in</span> cur <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If the start of the word matches the leaf</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> word.<span style="color: #006600;">indexOf</span><span style="color:#008800; font-weight:bold;">&#40;</span> node <span style="color:#008800; font-weight:bold;">&#41;</span> === <span style="color: #CC0000;">0</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If it's a number</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> val = <span style="color: #000066; font-weight: bold;">typeof</span> cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span> === <span style="color: #3366CC;">"number"</span> &amp;&amp; cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span> ?<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Substitute in the removed suffix object</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; dict.$<span style="color:#008800; font-weight:bold;">&#91;</span> cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#93;</span> :</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Otherwise use the current value</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; cur<span style="color:#008800; font-weight:bold;">&#91;</span> node <span style="color:#008800; font-weight:bold;">&#93;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If this leaf finishes the word</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> node.<span style="color: #006600;">length</span> === word.<span style="color: #006600;">length</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Return 'true' only if we've reached a final leaf</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> val === <span style="color: #CC0000;">0</span> || val.$ === <span style="color: #CC0000;">0</span>;</p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Otherwise continue traversing deeper</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// down the tree until we find a match</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> findTrieWord<span style="color:#008800; font-weight:bold;">&#40;</span> word.<span style="color: #006600;">slice</span><span style="color:#008800; font-weight:bold;">&#40;</span> node.<span style="color: #006600;">length</span> <span style="color:#008800; font-weight:bold;">&#41;</span>, val <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>Note that we have to do the <code>indexOf</code> and <code>slice</code> operations on the word in order to get at the proper substrings that we need for comparison. Additionally we have to make sure that we substitute in the suffix objects that we've removed previously. In all it's likely to add some level of performance overhead, compared with a traditional Trie, but considering how fast it is already that hit really ends up being negligible.</p>
<p><strong>Further File Size Optimization</strong></p>
<p>I did two final tweaks to save on file size. First, I remove all the quotes in the file. Yes, this makes it no longer valid JSON - but that's OK for my particular situation (I'm loading it as a JavaScript file). Second, I go through and re-quote all the reserved words that are used as object property names. Thus <code>{ for: 0, in: 0, zoo: 0 }</code> would become: <code>{ 'for': 0, 'in': 0, zoo: 0 }</code>. This final result makes the best use of file size while still working properly in all browsers.</p>
<h2>File Size Analysis</h2>
<p>The biggest win provided by a Trie should be related to its decrease in file size. The plain string dictionary contained 112,429 words in it and clocked in at 916KB so it seems like any decrease should be possible.</p>
<p>I did multiple levels of comparison. Comparing the basic string version of the dictionary (that I discussed in the last blog post), the simple Trie (no optimizations), the optimized Trie, and the suffix optimized Trie.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5532655877/" title="Dictionary File Size Comparison by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5096/5532655877_d095d57b98.jpg" width="500" height="375" alt="Dictionary File Size Comparison" /></a></center></p>
<p>The result is quite interesting. The unoptimized, uncompressed, Trie is actually slightly larger than the plain dictionary - but shows some solid benefits once compressed. The further optimizations yield even better results. The final suffix optimized, gzipped, Trie yields a file size of 155KB compared to the initial 276KB of the plain string dictionary. Not bad for over 110,000 words!</p>
<h2>Load Speed Analysis</h2>
<p>If I was only interested in the download size of the dictionary I would've stopped there - however I want to make sure that no other aspect of the application will be hurt by making this switch. Specifically I want to make sure that loading in the dictionary (converting it from a serialized JS string into a usable form) was still fast. I want to make sure that when I do an Ajax request to get the dictionary, or when I load the dictionary from localStorage, the resulting overhead of parsing all the code doesn't cripple the application.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5533237722/" title="Dictionary Load Speed Comparison by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5013/5533237722_02cf2e16ee.jpg" width="500" height="375" alt="Dictionary Load Speed Comparison" /></a></center></p>
<p>Unfortunately this is where we start to see some serious problems with using anything but a plain string. In the above chart I include the plain string dictionary and the Trie - but also the hash-lookup technique that I described in my last post.</p>
<p>Note that this load process is going to happen every time the application starts (for example having to re-parse the serialized Trie into a usable JavaScript object).</p>
<p>In the above chart I'm only analyzing the code in one of the fastest JavaScript environments in existence: an unhindered Node.js running on a Core i7 processor - and even then loading the Trie dictionary takes over 100ms. I fear how long it would take on a mobile phone or in an older Internet Explorer browser. If you're wondering why this might be the case think about what's happening here: You're loading and evaluating over 506KBs (after being un-gzipped) of JavaScript code. This will bog down any system - especially a phone.</p>
<p>To drive the point home I ran some tests in some browsers:</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5533398417/" title="Load Speed of Trie by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5019/5533398417_e70338093b.jpg" width="500" height="375" alt="Load Speed of Trie" /></a></center></p>
<p>Sure enough - even one of the fastest mobile browsers (Mobile Safari 4.3) takes <strong>over 4 seconds</strong> to load the Trie data structure! In fact it crashed the browser on a few test runs.</p>
<p>Considering that Gmail <a href="http://www.stevesouders.com/blog/2009/09/26/mobile-gmail-and-async-script-loading/">delays nearly all execution of its JavaScript code</a>, on mobile devices, requiring 506KBs of JavaScript code to be executed up front becomes untenable.</p>
<h2>Search Speed Analysis</h2>
<p>I didn't want to stop there, though. There were (justified) concerns in reply to the previous post regarding the lookup technique being employed to find words in the plain string dictionary (it was using a simple indexOf operation). This is a linear search through the string and will undoubtedly be much slower than using a Hash or a Trie lookup.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5532656255/" title="Dictionary Search Speed Comparison by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5172/5532656255_27fcc758e9.jpg" width="500" height="375" alt="Dictionary Search Speed Comparison" /></a></center></p>
<p>I ran some tests (for both finding valid words and invalid words) and confirmed that suspicion: Doing a linear search across a plain string is fundamentally much slower than using a hash or a Trie. However - note the time scale. In the absolute worst case searching the plain string dictionary for a word yielded lookup times of less than one millisecond. Considering that in my game dictionary lookups are only happening every couple seconds (and not thousands of times a second) I can get away with this performance hit. Presumably if you were building a game that required multitudes of dictionary lookups you might want to go with a faster hash or Trie technique.</p>
<h2>Memory Usage Analysis</h2>
<p>Finally I decided to take a look at memory usage. This was one last factor that I needed to take into account, with regards to mobile. Using too much memory will cause a web site to reload if the user switches tabs on an iOS device - and will likely cause similar problems on other mobile devices.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5532656099/" title="Dictionary Memory Usage Comparison by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5056/5532656099_6e06470f98.jpg" width="500" height="375" alt="Dictionary Memory Usage Comparison" /></a></center></p>
<p>Once again, having a simple object yields some impressive gains. Using just a plain string (even though it's 916KB) still ends up using less than half the amount of memory that a Trie structure does - and almost 10x less than a naïve hash.</p>
<p><strong>Raw Memory Usage Data:</strong></p>
<p>(I loaded the dictionary 100 times in Node.js in each case in order to try and get an accurate reading from OS X's Activity Monitor monitor application.)</p>
<p>Baseline memory usage of an empty Node.js application:</p>
<p><img src="http://gyazo.com/6c9a61f5aa5c7260d09bbe7a0fc1b5f2.png"/></p>
<p>Memory usage of a the plain string technique:</p>
<p><img src="http://gyazo.com/3baaf881b744190e2e656a8e9d40d6cd.png"/></p>
<p><small>(Note that even though I loaded the dictionary 100 times it appears to have been smart and cut down on duplicate memory usage. I even tried to inject some randomness into the dictionary string but still ended up with similar results. I ended up just counting this result once, rather than dividing by 100 like with the other results.)</small></p>
<p>Memory usage of the hash technique:</p>
<p><img src="http://gyazo.com/1c4ab07f7501ec2763e91de35b43851f.png"/></p>
<p>Memory usage of using a Trie:</p>
<p><img src="http://gyazo.com/dbe9532a2cdd61fd28207f6e80e40a5e.png"/></p>
<h2>Conclusion</h2>
<p>So while utilizing a Trie structure could yield some rather significant file size and word lookup performance improvements - it comes at a cost that is rather unacceptable for an application that's attempting to target older browsers or mobile devices (both in terms of initial load and in terms of memory usage).</p>
<p>I hope the <a href="https://github.com/jeresig/trie-js">Trie JavaScript code</a> that I've written can be useful to some either way.</p>
<p>If anything though, I hope to communicate that when you are making decisions about what technologies to use - just because something may sound better on paper you really should do some careful analysis of the solution before moving ahead.</p>
<h3>Raw Data</h3>
<p>The raw data for all my tests (which can be found <a href="https://github.com/jeresig/trie-js">in my Trie.js Github repo</a>) is as follows:</p>
<p><small>
<pre>Plain String
--------------
Normal: 916KB
Gzipped: 276KB
Build Speed: 1 (.01 per)
Find Speed: 47331 (0.42ms per)
Not Find Speed: 71902 (0.64ms per)
Private Memory: 10.3MB (1.2MB per)

Hash
--------------
Normal: 916KB
Gzipped: 276KB
Hash Build Speed: 6638 (66.4 per)
Hash Find Speed: 19 (0.0002ms per)
Hash Not Find Speed: 34 (0.0003ms per)
Private Memory: 1014MB (10.05MB per)

Trie
--------------
Simple Trie: 1.0MB
Gzipped: 184KB

Optimized Trie: 761KB
Gzipped: 168KB

Suffix Optimized Trie: 506KB
Gzipped 155KB
Build Speed: 11178 (111.8 per)
Find Speed: 413 (0.004 per)
Not Find Speed: 552 (0.005 per)
Private Memory: 299.2MB (2.9MB per)</pre>
<p></small></p>
<p><strong>Update:</strong> Early this morning Mike Koss posted a follow-up on my previous blog post with a <a href="http://lookups.pageforest.com/">compressed Trie implementation</a>. This is quite interesting and will certainly result in a smaller file size than what I've done. However, there's a problem: The result will end up taking a longer amount of time to load than the plain JavaScript structure that I employed. In my solution, since it's already written using JavaScript syntax, the performance will run as fast as the JavaScript engine can parse the code. However in Mike's solution the corresponding JavaScript structure will need to be re-built from the text itself. Theoretically if Mike comes up with a solution that used the compressed file size but leaves the data in its original string - that would be the best of all worlds. I'll be curious to see what he comes up with!</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/o9zyQSz65M8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/javascript-trie-performance-analysis/feed/</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>Dictionary Lookups in JavaScript</title>
		<link>http://ejohn.org/blog/dictionary-lookups-in-javascript/</link>
		<comments>http://ejohn.org/blog/dictionary-lookups-in-javascript/#comments</comments>
		<pubDate>Tue, 15 Mar 2011 23:14:56 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5727</guid>
		<description><![CDATA[I've been working on a browser-based word game, naturally written in JavaScript, and have been encountering some interesting technical challenges along the way. I've written up my thought process here for others to learn from (note that most of this happened over the course of a month, or so). I've often found that while a [...]]]></description>
			<content:encoded><![CDATA[<p>I've been working on a browser-based word game, naturally written in JavaScript, and have been encountering some interesting technical challenges along the way. I've written up my thought process here for others to learn from (note that most of this happened over the course of a month, or so). I've often found that while a final solution to a problem may be rather elegant and "make perfect sense" when looking at it - it's only through the result of much trial and error that the solution was arrived upon.</p>
<p>To start, in my game, the user is frequently re-arranging letters - causing the game to look up words in a dictionary to see if they are valid, or not.</p>
<p>I've taken multiple passes at implementing a solution to this problem, ranging all the way from "I don't care about performance, I just want it to work" all the way up to "thousands of people could be playing simultaneously, how do I scale?"</p>
<p>For my seed dictionary I used a variation of the Scrabble dictionary, which can be found via some <a href="https://encrypted.google.com/search?q=scrabble+dictionary+txt">creative Googling</a>. The full dictionary ends up being around 916KB (with words separated by an endline).</p>
<h2>Server-Side Solution</h2>
<p>The first pass was stupid simple. It worked, but just barely. I took the dictionary and split it up into 26 files - one for each letter of the alphabet - and put all the words that started with the corresponding letter in the text file.</p>
<p>I then made a little PHP script to handle user requests - reading in the portion of the dictionary file and returning "pass" or "fail" if the word was found.</p>
<div class="syntax_hilite">
<div id="php-42">
<div><span style="color: #000000; font-weight: bold;">&lt;?php</span><br />
&nbsp; <span style="color:#008000;"># Get the word to be checked from the user</span><br />
&nbsp; <span style="color: #0000ff;">$word</span> = <span style="color: #0000ff;">$_GET</span><span style="color:#008800; font-weight:bold;">&#91;</span><span style="color: #ff0000;">'word'</span><span style="color:#008800; font-weight:bold;">&#93;</span>;<br />
&nbsp; <br />
&nbsp; <span style="color:#008000;"># Get the first letter of that word</span><br />
&nbsp; <span style="color: #0000ff;">$first</span> = <a href="http://www.php.net/substr"><span style="color: #000066;">substr</span></a><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #0000ff;">$word</span>, <span style="color:#800000;">0</span>, <span style="color:#800000;">1</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p>&nbsp; <span style="color:#008000;"># Open the corresponding file</span><br />
&nbsp; <span style="color: #0000ff;">$handle</span> = <a href="http://www.php.net/fopen"><span style="color: #000066;">fopen</span></a><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #ff0000;">"words/"</span> . <span style="color: #0000ff;">$first</span> . <span style="color: #ff0000;">".txt"</span>, <span style="color: #ff0000;">"r"</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color: #b1b100;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #0000ff;">$handle</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color:#008000;"># Keep going until the end of the file</span><br />
&nbsp; &nbsp; <span style="color: #b1b100;">while</span> <span style="color:#008800; font-weight:bold;">&#40;</span>!<a href="http://www.php.net/feof"><span style="color: #000066;">feof</span></a><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #0000ff;">$handle</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000;"># Get the word in the dictionary</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000;"># (removing the endline)</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">$line</span> = <a href="http://www.php.net/trim"><span style="color: #000066;">trim</span></a><span style="color:#008800; font-weight:bold;">&#40;</span><a href="http://www.php.net/fgets"><span style="color: #000066;">fgets</span></a><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #0000ff;">$handle</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000;"># And see if the word matches</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #b1b100;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #0000ff;">$line</span> == <span style="color: #0000ff;">$word</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008000;"># If so return &quot;pass&quot; to the client</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #ff0000;">"pass"</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.php.net/exit"><span style="color: #000066;">exit</span></a><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <a href="http://www.php.net/fclose"><span style="color: #000066;">fclose</span></a><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #0000ff;">$handle</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; <span style="color:#008000;"># If we made it to the end, then we failed</span><br />
&nbsp; <a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #ff0000;">"fail"</span>;<br />
<span style="color: #000000; font-weight: bold;">?&gt;</span></div>
</div>
</div>
<p>(Please don't use the above code, it's terrible.)</p>
<p>Thus you would call the PHP script like so:</p>
<p><code>/words.php?word=test</code></p>
<p>And it would return either "pass" or "fail" (meaning that it would only work on the same domain).</p>
<p>So while the above worked it wasn't nearly fast enough and it consumed a ton of memory on the server - each request was reading in large portions of potentially 100KB+ files. Time for a better solution.</p>
<h2>A Better Server-Side Solution</h2>
<p>My next attempt was to write a simple little web server (in Perl, this time) that pre-loaded the entire dictionary into memory, and handled all the requests via JSONP.</p>
<div class="syntax_hilite">
<div id="perl-41">
<div><span style="color: #808080; font-style: italic;">#!/usr/bin/perl</span></p>
<p><span style="color: #000000; font-weight: bold;">use</span> CGI;</p>
<p><span style="color: #808080; font-style: italic;"># Read the dictionary into the word hash</span><br />
<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">%words</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/map.html"><span style="color: #000066;">map</span></a> <span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$_</span>, <span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">&#125;</span> <a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span style="color: #000066;">split</span></a><span style="color: #66cc66;">&#40;</span>/\n/, `cat dict/dict.txt`<span style="color: #66cc66;">&#41;</span>;</p>
<p><span style="color: #808080; font-style: italic;"># Instantiate and start the web server</span><br />
<span style="color: #000000; font-weight: bold;">use</span> base <a href="http://www.perldoc.com/perl5.6/pod/func/qw.html"><span style="color: #000066;">qw</span></a><span style="color: #66cc66;">&#40;</span>Net::Server::HTTP<span style="color: #66cc66;">&#41;</span>;<br />
__PACKAGE__-&gt;<span style="color: #006600;">run</span><span style="color: #66cc66;">&#40;</span> port =&gt; <span style="color: #cc66cc;">8338</span> <span style="color: #66cc66;">&#41;</span>;</p>
<p><span style="color: #000000; font-weight: bold;">sub</span> process_http_request <span style="color: #66cc66;">&#123;</span><br />
&nbsp; <span style="color: #808080; font-style: italic;"># Make a CGI object for the request</span><br />
&nbsp; <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$cgi</span> = CGI-&gt;<span style="color: #006600;">new</span>;</p>
<p>&nbsp; <span style="color: #808080; font-style: italic;"># Get the word from the user</span><br />
&nbsp; <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$word</span> = <span style="color: #0000ff;">$cgi</span>-&gt;<span style="color: #006600;">param</span><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">"word"</span> <span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; <span style="color: #0000ff;">$word</span> =~ <a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>/\W//g;</p>
<p>&nbsp; <span style="color: #808080; font-style: italic;"># And the callback name</span><br />
&nbsp; <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$callback</span> = <span style="color: #0000ff;">$cgi</span>-&gt;<span style="color: #006600;">param</span><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">"callback"</span> <span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; <span style="color: #0000ff;">$callback</span> =~ <a href="http://www.perldoc.com/perl5.6/pod/func/s.html"><span style="color: #000066;">s</span></a>/\W//g;</p>
<p>&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> <span style="color: #ff0000;">"Content-type: text/javascript<span style="color: #000099; font-weight: bold;">\n</span><span style="color: #000099; font-weight: bold;">\n</span>"</span>;</p>
<p>&nbsp; <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$word</span> &amp;&amp; <span style="color: #0000ff;">$callback</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Dump back the results in a JSONP format</span><br />
&nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span style="color: #000066;">print</span></a> <span style="color: #0000ff;">$callback</span> . <span style="color: #ff0000;">'({&quot;word&quot;:&quot;'</span> . <span style="color: #0000ff;">$word</span> .<br />
&nbsp; &nbsp; &nbsp; <span style="color: #ff0000;">'&quot;,&quot;pass&quot;:'</span> . <span style="color: #66cc66;">&#40;</span><a href="http://www.perldoc.com/perl5.6/pod/func/defined.html"><span style="color: #000066;">defined</span></a> <span style="color: #0000ff;">$words</span><span style="color: #66cc66;">&#123;</span> <span style="color: #0000ff;">$word</span> <span style="color: #66cc66;">&#125;</span> ?<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff0000;">'true'</span> : <span style="color: #ff0000;">'false'</span><span style="color: #66cc66;">&#41;</span> . <span style="color: #ff0000;">'})'</span>;<br />
&nbsp; <span style="color: #66cc66;">&#125;</span><br />
<span style="color: #66cc66;">&#125;</span></div>
</div>
</div>
<p>You would call the above using something like this:</p>
<p><code>http://example.com:8338/?word=test&#038;callback=wordFound</code></p>
<p>There are a bunch of things that I don't like about the above code (like using a hash to lookup the words, when more memory-efficient solutions exist, and instantiating a CGI object on every request - things like that). Also if I were to do this today I'd probably write it in <a href="http://nodejs.org/">Node.js</a>, which I'm becoming more familiar with.</p>
<p>Compared with the previous solution though there are a large number of advantages. Since the dictionary is being loaded into memory only once, and into a hash, it makes lookups very, very, fast. I was timing entire HTTP requests at only a handful of milliseconds, which is great. Additionally since this solution utilized JSONP it was possible to set up a server (or multiple servers) dedicated to looking up words and have the clients connect to them cross-domain.</p>
<h2>A Client-Side Solution</h2>
<p>It was at this point that I realized a couple problems with the previous server-side solutions. If my game was going to work offline (or as a distributable mobile application) then a constant connection to a dictionary server wasn't going to be possible. (And if slow mobile connections were taken into account then the responsiveness of the server just wasn't going to be sufficient enough.)</p>
<p>The dictionary was going to have to live on the client.</p>
<p>Thus I wrote a simple Ajax request to load the text dictionary and make a lookup object for later use.</p>
<div class="syntax_hilite">
<div id="js-36">
<div><span style="color: #009900; font-style: italic;">// The dictionary lookup object</span><br />
<span style="color: #003366; font-weight: bold;">var</span> dict = <span style="color:#008800; font-weight:bold;">&#123;</span><span style="color:#008800; font-weight:bold;">&#125;</span>;</p>
<p><span style="color: #009900; font-style: italic;">// Do a jQuery Ajax request for the text dictionary</span><br />
$.<span style="color: #006600;">get</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #3366CC;">"dict/dict.txt"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span> txt <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Get an array of all the words</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> words = txt.<span style="color: #006600;">split</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #3366CC;">"<span style="color: #000099; font-weight: bold;">\n</span>"</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p>&nbsp; <span style="color: #009900; font-style: italic;">// And add them as properties to the dictionary lookup</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// This will allow for fast lookups later</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #003366; font-weight: bold;">var</span> i = <span style="color: #CC0000;">0</span>; i &lt; words.<span style="color: #006600;">length</span>; i++ <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; dict<span style="color:#008800; font-weight:bold;">&#91;</span> words<span style="color:#008800; font-weight:bold;">&#91;</span>i<span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#93;</span> = <span style="color: #003366; font-weight: bold;">true</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// The game would start after the dictionary was loaded</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// startGame();</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p><span style="color: #009900; font-style: italic;">// Takes in an array of letters and finds the longest</span><br />
<span style="color: #009900; font-style: italic;">// possible word at the front of the letters</span><br />
<span style="color: #003366; font-weight: bold;">function</span> findWord<span style="color:#008800; font-weight:bold;">&#40;</span> letters <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Clone the array for manipulation</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> curLetters = letters.<span style="color: #006600;">slice</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #CC0000;">0</span> <span style="color:#008800; font-weight:bold;">&#41;</span>, word = <span style="color: #3366CC;">""</span>;<br />
&nbsp; <br />
&nbsp; <span style="color: #009900; font-style: italic;">// Make sure the word is at least 3 letters long</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">while</span> <span style="color:#008800; font-weight:bold;">&#40;</span> curLetters.<span style="color: #006600;">length</span> &gt; <span style="color: #CC0000;">2</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Get a word out of the existing letters</span><br />
&nbsp; &nbsp; word = curLetters.<span style="color: #006600;">join</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">""</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// And see if it's in the dictionary</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> dict<span style="color:#008800; font-weight:bold;">&#91;</span> word <span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// If it is, return that word</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> word;<br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Otherwise remove another letter from the end</span><br />
&nbsp; &nbsp; curLetters.<span style="color: #006600;">pop</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>Note that having the dictionary on the client actually allowed for an interesting new form of game play. Previously the player had to select a specific word and send it to the server - and only then would the server say if that word was valid or not. Since the dictionary now lives on the client (making lookups instantaneous, in comparison) we can change the logic a bit: The game now looks for the longest word at the start of the user's letters. For example, if the user had the letters "rategk" then the function would work like so:</p>
<div class="syntax_hilite">
<div id="js-37">
<div>findWord<span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color:#008800; font-weight:bold;">&#91;</span> <span style="color: #3366CC;">"r"</span>, <span style="color: #3366CC;">"a"</span>, <span style="color: #3366CC;">"t"</span>, <span style="color: #3366CC;">"e"</span>, <span style="color: #3366CC;">"g"</span>, <span style="color: #3366CC;">"k"</span> <span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#41;</span><br />
<span style="color: #009900; font-style: italic;">// =&gt; returns &quot;rate&quot;</span></p>
<p>findWord<span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color:#008800; font-weight:bold;">&#91;</span> <span style="color: #3366CC;">"k"</span>, <span style="color: #3366CC;">"t"</span>, <span style="color: #3366CC;">"a"</span>, <span style="color: #3366CC;">"g"</span>, <span style="color: #3366CC;">"e"</span>, <span style="color: #3366CC;">"k"</span> <span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#41;</span><br />
<span style="color: #009900; font-style: italic;">// =&gt; returns undefined </span><br />
&nbsp;</div>
</div>
</div>
<p>Naturally, something similar could've been done on the server-side - but that wasn't readily apparent when working on the server. This is a case where a performance optimization actually created a new, emergent, form of gameplay.</p>
<p>But here's the rub: We're now sending a massive dictionary down to a client. It's 916KB - and that's absolutely massive.</p>
<h2>Optimizing the Client-Side Solution</h2>
<p><strong>Compression and Caching</strong></p>
<p>Turning on Gzip compression on the server reduces the dictionary file size from 916KB to a much-more-sane 276KB. Additionally configuring the cache-control settings of your server will ensure that the dictionary won't be requested again for a very long time (assuming that the cache in the browser isn't cleared).</p>
<p>There are some excellent articles already written on these techniques:</p>
<ul>
<li><a href="http://www.websiteoptimization.com/speed/tweak/cache/">Configuring your Cache Settings in Apache</a></li>
<li><a href="http://www.cyberciti.biz/tips/speed-up-apache-20-web-access-or-downloads-with-mod_deflate.html">Configuring your Compression Settings in Apache</a></li>
<li>Julien Lecomte also wrote a <a href="http://www.julienlecomte.net/blog/2007/08/13/">useful PHP script to do both simultaneously</a></li>
</ul>
<p><strong>Content Delivery Networks</strong></p>
<p>Of course, all of this is a bit of a given when you use a <a href="http://developer.yahoo.com/blogs/ydn/posts/2007/04/high_performanc_1/">Content Delivery Network</a> - which I most certainly do. Right now I'm using Amazon Cloudfront, due to its relatively simple API, but I'm open to other solutions. This means that the dictionary file will be positioned on a large number of servers around the globe and served to the user in the fastest manner possible (using both gzip and proper cache headers).</p>
<p><strong>Cross-Domain Requests</strong></p>
<p>There's a problem, though: We can't load our dictionary from a CDN! Since the CDN is located on another server (or on another sub-domain, as is the case here) we're at the mercy of the browser's cross-origin policy prohibiting those types of requests. All is not lost though - with a simple tweak to the dictionary file we can load it across domains.</p>
<p>First, we replace all endlines in the dictionary file with a space. Second, we wrap the entire line with a JSONP statement. Thus the final result looks something like this:</p>
<p><code>dictLoaded('aah aahed aahing aahs aal... zyzzyvas zzz');</code></p>
<p>This allows us to do an Ajax request for the file and have it work as would expected it to - while still benefitting from all the caching and compression provided by the browser.</p>
<p>I alluded to another problem already: If the browser doesn't cache the file, for some reason, or if the cache runs out of space and the file is expunged - it'll be downloaded again. I want to try and reduce the number of times in which 216KB file will be downloaded - if not for the users then for reducing my bandwidth bill.</p>
<p><strong>Local Storage</strong></p>
<p>This is where we can use a great feature of HTML 5: Local Storage. Mark Pilgrim has a <a href="http://diveintohtml5.org/storage.html">great tutorial</a> written up on the subject that I recommend to all. In a crude nutshell: You now have an object that you can stuff strings into and they'll be persisted by the browser. Most browsers give you around 5MB to play with - which is more than enough for our dictionary file. It also has great cross-browser support - with the simple API working across all modern browsers.</p>
<p>With a little tweak to our Ajax logic (taking into account the JSONP request, the CDN, and Local Storage) we now end up with a revised solution:</p>
<div class="syntax_hilite">
<div id="js-38">
<div><span style="color: #009900; font-style: italic;">// See if the property that we want is pre-cached in the localStorage</span><br />
<span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> window.<span style="color: #006600;">localStorage</span> !== <span style="color: #003366; font-weight: bold;">null</span> &amp;&amp; window.<span style="color: #006600;">localStorage</span>.<span style="color: #006600;">gameDict</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; dictReady<span style="color:#008800; font-weight:bold;">&#40;</span> window.<span style="color: #006600;">localStorage</span>.<span style="color: #006600;">gameDict</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p><span style="color: #009900; font-style: italic;">// Load in the dictionary from the server</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; jQuery.<span style="color: #006600;">ajax</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; url: cdnHREF + <span style="color: #3366CC;">"dict/dict.js"</span>,<br />
&nbsp; &nbsp; dataType: <span style="color: #3366CC;">"jsonp"</span>,<br />
&nbsp; &nbsp; jsonp: <span style="color: #003366; font-weight: bold;">false</span>,<br />
&nbsp; &nbsp; jsonpCallback: <span style="color: #3366CC;">"dictLoaded"</span>,<br />
&nbsp; &nbsp; success: <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span> txt <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Cache the dictionary, if possible</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> window.<span style="color: #006600;">localStorage</span> !== <span style="color: #003366; font-weight: bold;">null</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; window.<span style="color: #006600;">localStorage</span>.<span style="color: #006600;">gameDict</span> = txt;<br />
&nbsp; &nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Let the rest of the game know</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// that the dictionary is ready</span><br />
&nbsp; &nbsp; &nbsp; dictReady<span style="color:#008800; font-weight:bold;">&#40;</span> txt <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// TODO: Add error/timeout handling</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>This gives us an incredibly efficient solution, allowing us to load the dictionary from a CDN (gzipped and with proper cache headers) - and avoiding subsequent requests to get the file if we already have it cached.</p>
<p><strong>Improving Memory Usage</strong></p>
<p>One final tweak that we can make. If you remember the previous dictionary lookup we loaded the entire dictionary into an object and then checked to see if a specific property existed. While this works, and is fast, it also ends up consuming a lot of memory (more so than the existing 916KB, at least).</p>
<p>To avoid this we can be a little bit tricky. Instead of putting the words into an object we can just leave the entire dictionary string intact and then do searches using a JavaScript String's indexOf method.</p>
<p>Thus inside the <code>dictReady</code> callback we'll have something like the following:</p>
<div class="syntax_hilite">
<div id="js-39">
<div><span style="color: #003366; font-weight: bold;">function</span> dictReady<span style="color:#008800; font-weight:bold;">&#40;</span> txt <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; dict = <span style="color: #3366CC;">" "</span> + txt + <span style="color: #3366CC;">" "</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>and our revised <code>findWord</code> function will look something like this:</p>
<div class="syntax_hilite">
<div id="js-40">
<div><span style="color: #009900; font-style: italic;">// Finding and extracting words</span><br />
<span style="color: #003366; font-weight: bold;">function</span> findWord<span style="color:#008800; font-weight:bold;">&#40;</span> letters <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// Copy all the tiles</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> curRack = letters.<span style="color: #006600;">slice</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #CC0000;">0</span> <span style="color:#008800; font-weight:bold;">&#41;</span>, word = <span style="color: #3366CC;">""</span>;</p>
<p>&nbsp; <span style="color: #009900; font-style: italic;">// We're going to keep going through the available letters</span><br />
&nbsp; <span style="color: #009900; font-style: italic;">// looking for a long-enough word</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">while</span> <span style="color:#008800; font-weight:bold;">&#40;</span> curRack.<span style="color: #006600;">length</span> &gt;= <span style="color: #CC0000;">3</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Find a &quot;word&quot; from the available tiles</span><br />
&nbsp; &nbsp; word = curRack.<span style="color: #006600;">join</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">""</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// ... and see if it's in the dictionary</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> dict.<span style="color: #006600;">indexOf</span><span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #3366CC;">" "</span> + word + <span style="color: #3366CC;">" "</span> <span style="color:#008800; font-weight:bold;">&#41;</span> &gt;= <span style="color: #CC0000;">0</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// We've found the word and we can stop</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> word;<br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// ... otherwise we need to remove the last letter</span><br />
&nbsp; &nbsp; curRack.<span style="color: #006600;">pop</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span></div>
</div>
</div>
<p>All together, as of this moment, this is the most optimal solution to this particular problem that I can think of. It's likely that I'll find some additional tweaks (or ways of improving memory usage) in the future - but at the very least this solution keeps HTTP requests to a minimum, bandwidth usage to a minimum, memory usage to a minimum, and lookups fast.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/MPrAVuqwF1Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/dictionary-lookups-in-javascript/feed/</wfw:commentRss>
		<slash:comments>59</slash:comments>
		</item>
		<item>
		<title>Learning from Twitter</title>
		<link>http://ejohn.org/blog/learning-from-twitter/</link>
		<comments>http://ejohn.org/blog/learning-from-twitter/#comments</comments>
		<pubDate>Thu, 20 Jan 2011 21:03:49 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5712</guid>
		<description><![CDATA[An issue popped up on Twitter this past week that caused the web site to be generally unusable for many users. It appears as if attempts to scroll were unbearably slow and caused the site to be unresponsive. The Twitter team investigated and determined that if they reverted the version of jQuery that they used [...]]]></description>
			<content:encoded><![CDATA[<p>An <a href="http://www.dustindiaz.com/about-that-slowness-on-twitter/">issue</a> popped up on Twitter this past week that caused the web site to be generally unusable for many users. It appears as if attempts to scroll were unbearably slow and caused the site to be unresponsive.</p>
<p>The Twitter team <a href="http://www.dustindiaz.com/about-that-slowness-on-twitter/">investigated</a> and determined that if they reverted the version of jQuery that they used back to 1.4.2 from 1.4.4 the site would be responsive again. After more investigation they determined that the code that was slow was doing a contextual selector search for an item by class name, for example: <code>$something.find(".class")</code>.</p>
<p>So - what happened? How did this come about? To start, nothing is inherently wrong with jQuery 1.4.4 - this particular performance regression came in jQuery 1.4.3. In 1.4.3 we switched from using the old Sizzle selector engine for contextual queries to using the browser's native querySelectorAll method, if it exists. This change was even <a href="http://blog.jquery.com/2010/10/16/jquery-143-released/">explicitly mentioned and highlighted</a> in the 1.4.3 release notes as it's a <em>really good change</em>. In general using querySelectorAll will result in much faster queries, especially for complicated queries and complicated documents (which there seem to be a lot of).</p>
<p>However, as with every performance change, while some things get way faster some things can also get slower. This was the case for some previously-optimized queries like .find(".class") (where we use getElementsByClassName, if it exists) and .find("div") (where we use getElementsByTagName). Both of those aforementioned methods always end up being faster than the queries run through querySelectorAll. Whether this will always end up being the case is another question entirely.</p>
<p>What's interesting here is that we've been using querySelectorAll for our default selector engine in jQuery for quite some time now (doing $('.class') would use querySelectorAll). The only change in 1.4.3 was just filling in a gap where .find('.class') wasn't using querySelectorAll. We've not heard of any particular performance regressions regarding the use of querySelectorAll and $('.class').</p>
<p>This brings up the important point: Just how much faster is getElementsByClassName compared to querySelectorAll? In our <a href="http://jsperf.com/jquery-context-find-class">preliminary tests</a> it looks like it's about 0.5-2x faster, depending upon the browser. While this is certainly nothing to scoff at the performance hit of this difference is quite negligible. For example the difference between searching by class name and querying in Firefox 3.6 is about 0.007s - certainly nothing that is capable of crippling a large application.</p>
<p>That being said, we don't like performance regressions so today we <a href="https://github.com/jeresig/sizzle/compare/f9491d4f7c1494cd19f865aff909fee21da321de...787b111c4743240bf042">backported some shortcuts</a> into Sizzle (from jQuery) to <a href="http://jsperf.com/jquery-context-find-class">improve its performance</a> for some common cases. For example: Sizzle("div"), Sizzle(".foo"), and Sizzle("#id") will all skip using querySelectorAll and try to use the native methods provided by the browser if they exist. (jQuery already did some of these (namely "div" and "#id", we just added the ".foo" shortcut as well).</p>
<p>So. If the performance hit wasn't very large then why was Twitter having so many problems? The reality is that this particular change was just the straw that broke the camel's back. Two things were happening that caused Twitter to have the issues that it was having. These can be distilled down into two general best practices:</p>
<h2>Best Practices</h2>
<p><strong>It's a very, very, bad idea to attach handlers to the window scroll event.</strong> Depending upon the browser the scroll event can fire <em>a lot</em> and putting code in the scroll callback will slow down any attempts to scroll the page (not a good idea). Any performance degradation in the scroll handler(s) as a result will only compound the performance of scrolling overall. Instead it's much better to use some form of a timer to check every X milliseconds OR to attach a scroll event and only run your code after a delay (or even after a given number of executions - and then a delay).</p>
<p><strong>Always cache the selector queries that you're re-using.</strong> It's not clear why Twitter decided to re-query the DOM every single time the scroll event fired, but this does not appear to be necessary (since scrolling itself didn't change the DOM). They could've saved the result of that single query to a variable and looked it up whenever they wanted to re-use. This would've resulted in absolutely no querying overhead (which is even better than having the faster getElementsByClassName code!).</p>
<p>Thus, combining these two techniques, the resulting code would look something like:</p>
<div class="syntax_hilite">
<div id="js-44">
<div><span style="color: #003366; font-weight: bold;">var</span> outerPane = $details.<span style="color: #006600;">find</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">".details-pane-outer"</span><span style="color:#008800; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; didScroll = <span style="color: #003366; font-weight: bold;">false</span>;</p>
<p>$<span style="color:#008800; font-weight:bold;">&#40;</span>window<span style="color:#008800; font-weight:bold;">&#41;</span>.<span style="color: #006600;">scroll</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; didScroll = <span style="color: #003366; font-weight: bold;">true</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p>setInterval<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color:#008800; font-weight:bold;">&#40;</span> didScroll <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; didScroll = <span style="color: #003366; font-weight: bold;">false</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Check your page position and then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900; font-style: italic;">// Load in more results</span><br />
&nbsp; &nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span><br />
<span style="color:#008800; font-weight:bold;">&#125;</span>, <span style="color: #CC0000;">250</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p>Hope this helps to clear things up and provides some good advice for future infinitely-scrolling-page developers!</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/oRBKvIEMNLE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/learning-from-twitter/feed/</wfw:commentRss>
		<slash:comments>50</slash:comments>
		</item>
		<item>
		<title>Google Cr-48 for Coding</title>
		<link>http://ejohn.org/blog/google-cr-48-for-coding/</link>
		<comments>http://ejohn.org/blog/google-cr-48-for-coding/#comments</comments>
		<pubDate>Fri, 10 Dec 2010 21:51:37 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/?p=5705</guid>
		<description><![CDATA[The other day I saw the announcement for the new Chrome OS test laptop and decided to sign up on the off-chance that I might be able to snag one. In the request form I made it very clear that I would be attempting to use this laptop for development (easily my primary activity). Surprisingly [...]]]></description>
			<content:encoded><![CDATA[<p>The other day I saw the announcement for the new Chrome OS test laptop and decided to sign up on the off-chance that I might be able to snag one. In the request form I made it very clear that I would be attempting to use this laptop for development (easily my primary activity). Surprisingly the laptop arrived this morning and I've been having fun putting it through its paces.</p>
<p>(Note: There doesn't appear to be a way to take screenshots of the Chrome OS UI - making this post a bit less interesting.)</p>
<h2>My Workflow</h2>
<p>I've seem to have settled upon a workflow that can work for me - to some limited extent. Chrome OS (as I'm sure you're aware) is roughly just enough operating system to get a copy of Chrome running. I've played with Chrome extensively before now so there wasn't anything that was too surprising. I had to install the PasswordMaker extension as I use it to manage all my passwords (thankfully one exists for Chrome, otherwise this laptop would be completely unusable to me).</p>
<p>Typically I have two pinned tabs in my browser: Gmail and Google Calendar. The OS doesn't appear to allow right-clicking so in order to make them pinned I had to add the Gmail and Calendar apps, tweak their options to only open pinned, and then re-open them.</p>
<p>Virtually all of my development is JavaScript-centric (and against Git repos). Thankfully it's easy enough to test JavaScript in Chrome OS - but development is another matter entirely. Right now there doesn't appear to be any good code editors (or file system access, for that matter). This puts a major damper on my ability to work offline.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5249459905/" title="Google Cr-48 Terminal by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5087/5249459905_261489e638.jpg" width="500" height="374" alt="Google Cr-48 Terminal" /></a></center></p>
<p>What I'm doing now is opening a separate terminal view (Ctrl+Alt+T) and SSH-ing to a server where I can develop. The terminal provided by Chrome OS is very very limited. The only truly useful command is 'ssh' and even then it's painfully limited. There is no way to provide an SSH key, for example (meaning that I actually had to set up an account on one of my servers with a password - which is quite lame). There does not appear to be any way to get a useful shell (sh, bash, tcsh - whatever). It seems as if there use to be some ways to boot into a different mode and get at the underlying Linux distro - but that all seems to be disabled on the Cr-48.</p>
<p>Right now I have my primary browser and my secondary terminal. In the terminal I have an SSH connection to my server where I run screen. Within that I split it into two vertical panes which gives me both a text editor and an IRC view (where I spend a vast majority of my day). Using this I can most likely get work done on a day-to-day basis.</p>
<p>The major problem: This really only works if you're connected to the Internet. I know that this should be rather obvious since this is 'Chrome OS' and it is something of a netbook - but the lack of any filesystem access means that I won't use this machine for anything more than a hobby (certainly can't use it while traveling).</p>
<p>I really like the Google Talk pop-overs that persist (making conversation rather easy). I didn't realize it at first but if you click the titlebar of a pop-over it will minimize, which is nice. However if I close a conversation it becomes an exercise in frustration to try and get it back.</p>
<p>Thankfully the Chrome in Chrome OS still has the developer tools installed, together with the JavaScript console.</p>
<p>I'm looking forward to when the Chrome OS store improves - right now it can be rather frustrating to do some simple things. For example I wanted to quickly crunch some numbers and went looking for a calculator. Surprisingly there wasn't one in the store. I ended up having to use the JavaScript console to do the calculations - which, I suspect, is not what Google expects most users to do.</p>
<h2>The Hardware</h2>
<p>Typically I use a Macbook Pro for my day-to-day development so I'm a bit spoiled when it comes to good hardware.</p>
<p>It appears as if the Cr-48 gets about 8 hours of battery life with the screen turned all the way down - or 6 hours with it all the way up. (Note: There is no brightness indicator when adjusting.) These numbers are about comparable to what I get on my Macbook (although I usually end up running more apps on the Macbook, including Textmate, a web server, and various other utilities).</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/5249460285/" title="Google Cr-48 by John Resig, on Flickr"><img src="http://farm6.static.flickr.com/5083/5249460285_0208674b39.jpg" width="500" height="374" alt="Google Cr-48" /></a></center></p>
<p>The trackpad is absolutely infuriating. It's as if Google attempted to create a similar trackpad to the Macbook Pro but just got it all wrong. There is two-finger scrolling (good) but no acceleration. Tap-to-click is frustrating and I disabled it immediately. There is no three-finger swipe-to-go-back gesture (which I miss a lot). Performing text selection is absolutely insane. It seems like any combination of having two fingers on the mouse pad simultaneously throws the laptop into "scroll" mode. It's so bad that it makes me not want to write things on the laptop until it is fixed. As mentioned before there appears to be physical way of doing a right click - but I can't find a single place in the UI where right-clicking has an effect.</p>
<p>I completely miss the power adapter from the Macbook. I've tripped over my cable dozens of times and the lack of a magnetic connector frightens me. Not to mention that the connector isn't very good to begin with - it's already fallen out at least once.</p>
<p>I've been having a mixed experience with the wireless. The regular (802.11) wireless seems to be really... forgetful. I've had to enter my wireless password at least a half dozen times today - and since my password is more of a "pass phrase" it becomes quite tedious. It seems to hate waking up from sleep, the wireless fails to reconnect quite frequently, in that case. That being said the 3G process is quite smooth. The setup is relatively easy and you get 2 years worth of free wireless from Google (this is for 100MB per month of usage). I'm already pleased with it and I'm looking forward to using it while sitting in the Boston Commons this summer (that, combined with the matte screen, will make this an amazing laptop for outdoor usage).</p>
<p>The keyboard is easily the best part of the Cr-48 hardware. Replacing Capslock with a "New Tab" button is truly inspired. I've found myself already starting to rely upon it very heavily. The keyboard feels good to type on and the large Ctrl + Alt keys make for easy key combinations (important when using screen).</p>
<h2>Conclusion</h2>
<p>As it stands the situation where I could see myself using the Cr-48 the most is if I were to casually explore a city or do work outside. The included 3G wireless and simplicity of design make it ideal for that. I do not plan on using this laptop for any travel (and, thus, I likely won't be using it for any presentations) until I can get some form of shell-based filesystem access. I'd love to be able to have access to a shell and the ability to install vim + screen + git + a web server. If I had that (and, presumably, this would be an easy thing for Google to do - probably just a switch that would need to be toggled) this laptop would easily become a top contender for my primary laptop.</p>
<p>Right now my ideal laptop would be: Take a 13" Macbook Pro, replace the HD with an SSD, replace the DVD drive with more battery, add 3G. I would use that laptop until the end of time.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/K_btXVYi6Hc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/google-cr-48-for-coding/feed/</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>Spring 2010 jQuery Talks</title>
		<link>http://ejohn.org/blog/spring-2010-jquery-talks/</link>
		<comments>http://ejohn.org/blog/spring-2010-jquery-talks/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 19:27:46 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://ejohn.org/blog/spring-2010-jquery-talks/</guid>
		<description><![CDATA[I gave a number of talks this spring on jQuery and especially on some of the recent additions made in jQuery 1.4. Below are all the slides and demos that I've given. The conferences / meetups that I spoke at (or will speak at, in the case of MIX), and the talks that I gave, [...]]]></description>
			<content:encoded><![CDATA[<p>I gave a number of talks this spring on jQuery and especially on some of the recent additions made in jQuery 1.4. Below are all the slides and demos that I've given.</p>
<p>The conferences / meetups that I spoke at (or will speak at, in the case of MIX), and the talks that I gave, are as follows:</p>
<ul>
<li><a href="http://www.webstock.org.nz/">Webstock</a> (Wellington, NZ) (Introduction to jQuery Workshop, Things You Might Not Know About jQuery)</li>
<li><a href="http://futureofwebapps.com/">Future of Web Apps</a> (Miami, FL) (Introduction to jQuery Workshop, Improve Your Web App with jQuery)</li>
<li><a href="http://meetups.jquery.com/group/jqueryboston">jQuery Boston Meetup</a> (Boston, MA) (Things You Might Not Know About jQuery)</li>
<li><a href="http://live.visitmix.com/MIX10">MIX</a> (Las Vegas, NV) (Improve Your Web App with jQuery)</li>
</ul>
<h2>Introduction to jQuery Workshop</h2>
<p>This workshop starts with an introduction to the fundamentals of jQuery (1 hour) and continues on with two pieces of hands-on coding (Todo list, 30 min, Social Networking Site, 1.5 hours).</p>
<p><center><a href="http://ejohn.org/apps/workshop/intro/" title="Introduction to jQuery by John Resig"><img src="http://farm5.static.flickr.com/4068/4406302927_26de54412c.jpg" width="500" height="391" alt="Introduction to jQuery" /></a><br/><a href="http://github.com/jeresig/jquery-workshop/tree/master/intro/">Source Code</a></center></p>
<p>In the workshop I also had two pieces of hands-on coding. The first was an ajax-y todo list the second was converting a functional social networking site into a one page application (making significant use of jQuery UI).</p>
<p><center><a href="http://ejohn.org/apps/workshop/todo/?action=done" title="jQuery Todo List by John Resig"><img src="http://farm5.static.flickr.com/4021/4407069694_46d16067a7_o.png" width="214" height="178" alt="jQuery Todo List" /></a><br/><a href="http://github.com/jeresig/jquery-workshop/tree/master/todo/">Source Code</a> <a href="http://ejohn.org/apps/workshop/todo/?action=reset">Reset Demo</a> <a href="http://ejohn.org/apps/workshop/todo/?action=edit">Edit Demo</a></center></p>
<p><center><a href="http://ejohn.org/apps/workshop/social/?action=done" title="jQuery Social Network by John Resig"><img src="http://farm5.static.flickr.com/4011/4407069738_ff0e296340.jpg" width="493" height="500" alt="jQuery Social Network" /></a><br/><a href="http://github.com/jeresig/jquery-workshop/tree/master/social/">Source Code</a> <a href="http://ejohn.org/apps/workshop/social/?action=reset">Reset Demo</a> <a href="http://ejohn.org/apps/workshop/social/?action=edit">Edit Demo</a></center></p>
<h2>Things You Might Not Know About jQuery</h2>
<p>A variety of things that people don't know about in jQuery - including new things added in jQuery 1.4 (and newer), data bindings, custom events, and special events.</p>
<p><center><a href="http://ejohn.org/apps/workshop/adv-talk/" title="Things You Might Not Know About jQuery by John Resig"><img src="http://farm5.static.flickr.com/4070/4407069574_87bbdf4da3.jpg" width="500" height="391" alt="Things You Might Not Know About jQuery" /></a><br/><a href="http://github.com/jeresig/jquery-workshop/tree/master/adv-talk/">Source Code</a></center></p>
<p>For the first jQuery Boston Meetup I built a game using the avatars of everyone in attendance. Sort of a space shooter style game you need to kick and kill the advancing hordes of users. I used this game as a way of demonstrating constructing an application that makes use of custom events, data binding, and building applications in an event-centric manner.</p>
<p><center><a href="http://ejohn.org/apps/workshop/adv-talk/game-done.html" title="jQuery Meetup Game by John Resig"><img src="http://farm5.static.flickr.com/4042/4407069620_957225ce0a.jpg" width="500" height="369" alt="jQuery Meetup Game" /></a><br/><a href="http://github.com/jeresig/jquery-workshop/blob/master/adv-talk/game-done.html">Source Code</a></center></p>
<h2>Improve Your Web App with jQuery</h2>
<p>A different restructuring of the previous talk that emphasizes a more holistic approach to improving your web applications with jQuery</p>
<p><center><a href="http://ejohn.org/apps/workshop/adv-talk/index2.html" title="Improve Your Web App with jQuery by John Resig"><img src="http://farm3.static.flickr.com/2779/4406302991_5b0be2c414.jpg" width="500" height="392" alt="Improve Your Web App with jQuery" /></a><br/><a href="http://github.com/jeresig/jquery-workshop/tree/master/adv-talk/">Source Code</a></center></p>
<p>I've been messing around with a new piece of presentation software that I wrote for these talks. It's still terribly crude and buggy (pretty much just got it working enough in order to run my talks in Firefox 3.6 and Chrome) - you've been warned. I hope to refine it at some point and release it for general consumption.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/CdFJtCipe1M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/spring-2010-jquery-talks/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>.closest(Array) in jQuery 1.4</title>
		<link>http://ejohn.org/blog/closestarray-in-jquery-14/</link>
		<comments>http://ejohn.org/blog/closestarray-in-jquery-14/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 22:31:17 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://ejohn.org/blog/closestarray-in-jquery-14/</guid>
		<description><![CDATA[A new method signature is slated for jQuery 1.4: .closest(Array). It builds upon the previous .closest() method and hyper-optimizes the logic needed for handling event delegation (and live events). closest() (and by extension, is()) has become a critical function in jQuery. With more people using live events reducing any overhead has become of the utmost [...]]]></description>
			<content:encoded><![CDATA[<p>A new method signature is slated for jQuery 1.4: .closest(Array). It builds upon the previous .closest() method and hyper-optimizes the logic needed for handling event delegation (and live events).</p>
<p><a href="http://docs.jquery.com/Traversing/closest">closest()</a> (and by extension, <a href="http://docs.jquery.com/Traversing/is">is()</a>) has become a critical function in jQuery. With more people using live events reducing any overhead has become of the utmost importance. Every time an event fires that live is bound to (such as click or mousemove) jQuery uses the closest() method to go from the target element and find the nearest element that matches the specific selector. The more handlers that are bound, though, the more computationally expensive it becomes.</p>
<p>In jQuery 1.4 we've <a href="http://github.com/jquery/jquery/blob/c05712f0a51a137c9243cbc33b4cb0d5d853a80d/src/traversing.js#L84">added closest(Array)</a> which gives us the ability to batch these selector checks together and reduce the amount of time that we spend traversing the DOM.</p>
<h3>Example</h3>
<div class="syntax_hilite">
<div id="html-47">
<div><span style="color: #009900;"><a href="http://december.com/html/4/element/html.html"><span style="color: #000000; font-weight: bold;">&lt;html&gt;</span></a></span><br />
&nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/body.html"><span style="color: #000000; font-weight: bold;">&lt;body&gt;</span></a></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">"main"</span><a href="http://december.com/html/4/element/.html"><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">"test"</span><a href="http://december.com/html/4/element/.html"><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">"mouseme"</span><a href="http://december.com/html/4/element/.html"><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html&gt;</span></span></div>
</div>
</div>
<p>And the following handlers are bound:</p>
<div class="syntax_hilite">
<div id="js-48">
<div>$<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"#mouseme"</span><span style="color:#008800; font-weight:bold;">&#41;</span>.<span style="color: #006600;">live</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"mousemove"</span>, ...<span style="color:#008800; font-weight:bold;">&#41;</span><br />
$<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"#main"</span><span style="color:#008800; font-weight:bold;">&#41;</span>.<span style="color: #006600;">live</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"mousemove"</span>, ...<span style="color:#008800; font-weight:bold;">&#41;</span><br />
$<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"body"</span><span style="color:#008800; font-weight:bold;">&#41;</span>.<span style="color: #006600;">live</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"mousemove"</span>, ...<span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color: #009900; font-style: italic;">// (plugin A)</span><br />
$<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"body"</span><span style="color:#008800; font-weight:bold;">&#41;</span>.<span style="color: #006600;">live</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"mousemove"</span>, ...<span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color: #009900; font-style: italic;">// (plugin B) </span><br />
&nbsp;</div>
</div>
</div>
<p>Let's pretend that a 'mousemove' event occurs on #mouseme.</p>
<p><strong>In jQuery 1.3.2:</strong></p>
<ol>
<li>#mouseme check on #mouseme (load Sizzle)</li>
<li>Return.</li>
<li>#main check on #mouseme (load Sizzle)</li>
<li>Walk up tree.</li>
<li>#main check on #test (load Sizzle)</li>
<li>Walk up tree.</li>
<li>#main check on #main (load Sizzle)</li>
<li>Return.</li>
<li>body check on #mouseme (load Sizzle)</li>
<li>Walk up tree.</li>
<li>body check on #test (load Sizzle)</li>
<li>Walk up tree.</li>
<li>body check on #main(load Sizzle)</li>
<li>Walk up tree.</li>
<li>body check on body (load Sizzle)</li>
<li>Return.</li>
<li>body check on #mouseme (load Sizzle)</li>
<li>Walk up tree.</li>
<li>body check on #test (load Sizzle)</li>
<li>Walk up tree.</li>
<li>body check on #main(load Sizzle)</li>
<li>Walk up tree.</li>
<li>body check on body (load Sizzle)</li>
<li>Return.</li>
<li><a href="http://github.com/jquery/jquery/blob/f93df73a76b60ce3459113582125adbafcb9614f/src/event.js#L574">Sort all element results.</a></li>
<li>Loop through the results to trigger.</li>
</ol>
<p><strong>In jQuery 1.4:</strong></p>
<ol>
<li>#mouseme check on #mouseme (load Sizzle)</li>
<li>#main check on #mouseme (load Sizzle)</li>
<li>body check on #mouseme (load Sizzle)</li>
<li>Walk up tree.</li>
<li>#main check on #test (load Sizzle)</li>
<li>body check on #test (load Sizzle)</li>
<li>Walk up tree.</li>
<li>#main check on #main (load Sizzle)</li>
<li>body check on #main (load Sizzle)</li>
<li>Walk up tree.</li>
<li>body check on body (load Sizzle)</li>
<li>Return.</li>
<li>Loop through the results to trigger.</li>
</ol>
<p>In summary: There is less walking up the tree, no running of duplicate selectors, and no sorting of element results.</p>
<p>We're still on track to push out a new alpha very soon and the final release on January 14th.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/uRxbgvWv8Nw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/closestarray-in-jquery-14/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>.nodeName Case Sensitivity</title>
		<link>http://ejohn.org/blog/nodename-case-sensitivity/</link>
		<comments>http://ejohn.org/blog/nodename-case-sensitivity/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 23:08:21 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://ejohn.org/blog/nodename-case-sensitivity/</guid>
		<description><![CDATA[When working with the DOM .nodeName property there are two hard-and-fast rules that most people abide by: The node names of HTML elements are always uppercase, even if they're explicitly created using lowercase characters. &#60;html&#62; will result in a .nodeName === "HTML" (see the HTML 5 draft). The node names of XML elements are always [...]]]></description>
			<content:encoded><![CDATA[<p>When working with the DOM <code>.nodeName</code> property there are two hard-and-fast rules that most people abide by:</p>
<ol>
<li>The node names of HTML elements are always uppercase, even if they're explicitly created using lowercase characters. <code>&lt;html&gt;</code> will result in a <code>.nodeName === "HTML"</code> (<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#apis-in-html-documents">see the HTML 5 draft</a>).</li>
<li>The node names of XML elements are always in the original case, as specified when they're created. <code>&lt;data&gt;</code> will result in a <code>.nodeName === "data"</code>, <code>&lt;DATA&gt;</code> will result in a <code>.nodeName === "DATA"</code>.</li>
</ol>
<p>Knowing these rules can be useful because it allows you to optimize your code. If you know that you're in an HTML document you can avoid having to upper/lowercase your <code>.nodeName</code> checks and you can just always assume that you're dealing with a <code>.nodeName</code> that's uppercase. This results in faster selectors for Internet Explorer and other minor optimizations.</p>
<p>However recently I've been running across two cases that've been especially problematic and have bucked the trend.</p>
<h2>Importing Nodes from XML</h2>
<p>The first is for browsers that support the <code>adoptNode</code>/<code>importNode</code> DOM methods. These methods allow you to move (or clone) a node from one DOM document to another. In this way you can move an XML node from an XML document and insert it into an HTML document. Normally this shouldn't matter much but, as it turns out, the original <code>.nodeName</code> case sensitivity is preserved from the original XML-ness of the node.</p>
<p>Thus if you have a lowercase XML element (<code>&lt;data&gt;</code>) and you use <code>adoptNode</code> or <code>importNode</code> to bring it into your HTML document the result will be <code>.nodeName === "data"</code> -- which completely bucks the trend for "all HTML element's node names are always uppercase." I consider this to be a bug, considering that the DOM element is now in an HTML document, not in an XML document, and should behave as such.</p>
<h2>Unknown HTML 5 Elements</h2>
<p>The second bit of weirdness comes from people attempting to use the new elements from HTML 5 in browsers that don't support it. Most browsers behave perfectly well when using some of the new HTML 5 elements (in that they don't freak out and support some level of styling). For Internet Explorer you must use the <a href="http://ejohn.org/blog/html5-shiv/">HTML 5 Shim</a> technique - this will give unknown HTML 5 elements the ability to be styled and hold contents (such as a <code>&lt;section&gt;</code> element).</p>
<p>However there is an additional gotcha: When Internet Explorer encounters an element that it doesn't recognize it leaves the <code>.nodeName</code> in its original case. Thus if you have a <code>&lt;section&gt;</code> element in your HTML page the result will be <code>.nodeName === "section"</code> -- which directly contradicts the normal case sensitivity of the <code>.nodeName</code> property in HTML documents.</p>
<p>To try and understand all of this I made a bunch of test cases using a number of doctypes and document styles.</p>
<ul>
<li><a href="http://ejohn.org/files/bugs/nodeName/html5.html">HTML 5 document</a> - uses the <a href="http://ejohn.org/blog/html5-doctype/">HTML 5 Doctype</a>.</li>
<li><a href="http://ejohn.org/files/bugs/nodeName/xhtml.html">XHTML document served as text/html</a>.</li>
<li><a href="http://ejohn.org/files/bugs/nodeName/quirks.html">HTML document served with no doctype</a>.</li>
<li><a href="http://ejohn.org/files/bugs/nodeName/xhtml.xhtml">XHTML document served with correct mimetype</a>.</li>
</ul>
<p>The important part of the test page is quite simple:</p>
<div class="syntax_hilite">
<div id="html-59">
<div><span style="color: #00bbdd;">&lt;!DOCTYPE html&gt;</span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/html.html"><span style="color: #000000; font-weight: bold;">&lt;html&gt;</span></a></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/head.html"><span style="color: #000000; font-weight: bold;">&lt;head&gt;</span></a></span><br />
&nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/title.html"><span style="color: #000000; font-weight: bold;">&lt;title&gt;</span></a></span>Testing nodeName<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head&gt;</span></span><br />
<span style="color: #009900;"><a href="http://december.com/html/4/element/body.html"><span style="color: #000000; font-weight: bold;">&lt;body&gt;</span></a></span><br />
&nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div</span></a> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">"test"</span><a href="http://december.com/html/4/element/.html"><span style="color: #000000; font-weight: bold;">&gt;</span></a></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;div&gt;</span></a></span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span><span style="color: #009900;"><a href="http://december.com/html/4/element/div.html"><span style="color: #000000; font-weight: bold;">&lt;DIV&gt;</span></a></span><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DIV&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;section&gt;</span><span style="color: #009900;"><a href="http://december.com/html/4/element/.html"><span style="color: #000000; font-weight: bold;">&lt;</span></a>/section&gt;</span><span style="color: #009900;">&lt;SECTION&gt;</span><span style="color: #009900;"><a href="http://december.com/html/4/element/.html"><span style="color: #000000; font-weight: bold;">&lt;</span></a>/SECTION&gt;</span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body&gt;</span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html&gt;</span></span></div>
</div>
</div>
<p>and the test cases are as follows:</p>
<p><strong>HTML</strong></p>
<p>Accesses the HTML elements that were originally included the page (should be case insensitive).</p>
<div class="syntax_hilite">
<div id="js-60">
<div>runTest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"HTML"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> document.<span style="color: #006600;">getElementById</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"test"</span><span style="color:#008800; font-weight:bold;">&#41;</span>.<span style="color: #006600;">childNodes</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p><strong>HTML createElement</strong></p>
<p>Creates new DOM elements using the same document as the page in which it was shipped (should be case insensitive).</p>
<div class="syntax_hilite">
<div id="js-61">
<div>runTest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"HTML createElement"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color:#008800; font-weight:bold;">&#91;</span>&nbsp; &nbsp; <br />
&nbsp; &nbsp; document.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"div"</span><span style="color:#008800; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; document.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"DIV"</span><span style="color:#008800; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; document.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"section"</span><span style="color:#008800; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; document.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"SECTION"</span><span style="color:#008800; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#93;</span>;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p><strong>innerHTML</strong></p>
<p>Attempts to inject the elements using <code>.innerHTML</code> (should be case insensitive).</p>
<div class="syntax_hilite">
<div id="js-62">
<div>runTest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"innerHTML"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> test = document.<span style="color: #006600;">getElementById</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"test"</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; test.<span style="color: #006600;">innerHTML</span> = <span style="color: #3366CC;">"&lt;div&gt;&lt;/div&gt;&lt;DIV&gt;&lt;/DIV&gt;"</span> + <br />
&nbsp; &nbsp; <span style="color: #3366CC;">"&lt;section&gt;&lt;/section&gt;&lt;SECTION&gt;&lt;/SECTION&gt;"</span>;<br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> test.<span style="color: #006600;">childNodes</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p>For the remaining tests I grab a simple XML document:</p>
<div class="syntax_hilite">
<div id="xml-68">
<div><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;</span>?xml <span style="color: #000066;">version</span>=<span style="color: #ff0000;">"1.0"</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">"UTF-8"</span>?<span style="font-weight: bold; color: black;">&gt;</span></span><br />
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;test<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;div<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/div<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;DIV<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/DIV<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;section<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/section<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;SECTION<span style="font-weight: bold; color: black;">&gt;</span></span></span><span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/SECTION<span style="font-weight: bold; color: black;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="font-weight: bold; color: black;">&lt;/test<span style="font-weight: bold; color: black;">&gt;</span></span></span></div>
</div>
</div>
<p>like so:</p>
<div class="syntax_hilite">
<div id="js-63">
<div><span style="color: #003366; font-weight: bold;">var</span> xhr = window.<span style="color: #006600;">XMLHttpRequest</span> ?<br />
&nbsp; <span style="color: #003366; font-weight: bold;">new</span> XMLHttpRequest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span> :<br />
&nbsp; <span style="color: #003366; font-weight: bold;">new</span> ActiveXObject<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"Microsoft.XMLHTTP"</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p>xhr.<span style="color: #006600;">open</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"GET"</span>, <span style="color: #3366CC;">"test.xml"</span>, <span style="color: #003366; font-weight: bold;">false</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
xhr.<span style="color: #006600;">send</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #003366; font-weight: bold;">null</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</p>
<p><span style="color: #003366; font-weight: bold;">var</span> xml = xhr.<span style="color: #006600;">responseXML</span>;</div>
</div>
</div>
<p><strong>XML</strong></p>
<p>Test the elements in the XML document directly (should be case sensitive).</p>
<div class="syntax_hilite">
<div id="js-64">
<div>runTest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"XML"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> xml.<span style="color: #006600;">documentElement</span>.<span style="color: #006600;">childNodes</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p><strong>XML createElement</strong></p>
<p>Same as the HTML createElement but done using the XML document (should be case sensitive).</p>
<div class="syntax_hilite">
<div id="js-65">
<div>runTest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"XML createElement"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color:#008800; font-weight:bold;">&#91;</span>&nbsp; &nbsp; <br />
&nbsp; &nbsp; xml.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"div"</span><span style="color:#008800; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; xml.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"DIV"</span><span style="color:#008800; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; xml.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"section"</span><span style="color:#008800; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; xml.<span style="color: #006600;">createElement</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"SECTION"</span><span style="color:#008800; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#93;</span>;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p><strong>HTML via importNode</strong></p>
<p>This clones the nodes from the XML document, using <code>importNode</code>, and places them into the HTML document (should be case sensitive).</p>
<div class="syntax_hilite">
<div id="js-66">
<div>runTest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"HTML via importNode"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> test = document.<span style="color: #006600;">getElementById</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"test"</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color: #000066; font-weight: bold;">while</span> <span style="color:#008800; font-weight:bold;">&#40;</span> test.<span style="color: #006600;">firstChild</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; test.<span style="color: #006600;">removeChild</span><span style="color:#008800; font-weight:bold;">&#40;</span> test.<span style="color: #006600;">firstChild</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p>
<p>&nbsp; <span style="color: #003366; font-weight: bold;">var</span> nodes = xml.<span style="color: #006600;">documentElement</span>.<span style="color: #006600;">childNodes</span>, node;<br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color:#008800; font-weight:bold;">&#40;</span> <span style="color: #003366; font-weight: bold;">var</span> i = <span style="color: #CC0000;">0</span>; i &lt; nodes.<span style="color: #006600;">length</span>; i++ <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; node = document.<span style="color: #006600;">importNode</span><span style="color:#008800; font-weight:bold;">&#40;</span> nodes<span style="color:#008800; font-weight:bold;">&#91;</span>i<span style="color:#008800; font-weight:bold;">&#93;</span>, <span style="color: #003366; font-weight: bold;">false</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; test.<span style="color: #006600;">appendChild</span><span style="color:#008800; font-weight:bold;">&#40;</span> node <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; <span style="color: #000066; font-weight: bold;">return</span> test.<span style="color: #006600;">childNodes</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<p><strong>HTML via adoptNode</strong></p>
<p>This moves the nodes from the XML document, using <code>adoptNode</code>, and places them into the HTML document (should be case sensitive).</p>
<div class="syntax_hilite">
<div id="js-67">
<div>runTest<span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"HTML via adoptNode"</span>, <span style="color: #003366; font-weight: bold;">function</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color:#008800; font-weight:bold;">&#41;</span><span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> test = document.<span style="color: #006600;">getElementById</span><span style="color:#008800; font-weight:bold;">&#40;</span><span style="color: #3366CC;">"test"</span><span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color: #000066; font-weight: bold;">while</span> <span style="color:#008800; font-weight:bold;">&#40;</span> test.<span style="color: #006600;">firstChild</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; test.<span style="color: #006600;">removeChild</span><span style="color:#008800; font-weight:bold;">&#40;</span> test.<span style="color: #006600;">firstChild</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; <span style="color: #003366; font-weight: bold;">var</span> nodes = xml.<span style="color: #006600;">documentElement</span>.<span style="color: #006600;">childNodes</span>, node;<br />
&nbsp; <span style="color: #000066; font-weight: bold;">while</span> <span style="color:#008800; font-weight:bold;">&#40;</span> nodes.<span style="color: #006600;">length</span> <span style="color:#008800; font-weight:bold;">&#41;</span> <span style="color:#008800; font-weight:bold;">&#123;</span><br />
&nbsp; &nbsp; node = document.<span style="color: #006600;">adoptNode</span><span style="color:#008800; font-weight:bold;">&#40;</span> nodes<span style="color:#008800; font-weight:bold;">&#91;</span><span style="color: #CC0000;">0</span><span style="color:#008800; font-weight:bold;">&#93;</span> <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; &nbsp; test.<span style="color: #006600;">appendChild</span><span style="color:#008800; font-weight:bold;">&#40;</span> node <span style="color:#008800; font-weight:bold;">&#41;</span>;<br />
&nbsp; <span style="color:#008800; font-weight:bold;">&#125;</span></p>
<p>&nbsp; <span style="color: #000066; font-weight: bold;">return</span> test.<span style="color: #006600;">childNodes</span>;<br />
<span style="color:#008800; font-weight:bold;">&#125;</span><span style="color:#008800; font-weight:bold;">&#41;</span>;</div>
</div>
</div>
<h2>The Results</h2>
<p>I ran the following tests in IE 6, IE 7, IE 8, Firefox 3.5, Safari 4.0.3, Chrome 3.0.195, and Opera 10.10. Additionally I tested against <code>.tagName</code> in addition to <code>.nodeName</code> and found no discernible difference (you can run your own <code>.tagName</code> tests by appending a ?tagName to any test URL <a href="http://ejohn.org/files/bugs/nodeName/html5.html?tagName">like so</a>.)</p>
<link rel="stylesheet" href="http://ejohn.org/files/bugs/nodeName/style.css"/>
<div id="testgrid">
<p><strong><a href="http://ejohn.org/files/bugs/nodeName/html5.html">HTML 5 Document</a></strong></p>
<blockquote><p><strong>Note:</strong> The HTML 5, XHTML (served as HTML), and no-doctype pages all behaved identically to each other in every browser - thus I'm just going to not display the XHTML (as HTML) and no-doctype results as there wouldn't be anything interesting to show.</p></blockquote>
<p>Firefox, Safari, and Chrome all yielded the same results here: Bringing in elements from an external document maintains the case sensitive nature of the <code>.nodeName</code> property - which is unexpected.</p>
<table id="results">
<thead>
<tr id="results-head">
<th></th>
<th>&lt;div&gt;</th>
<th>&lt;DIV&gt;</th>
<th>&lt;section&gt;</th>
<th>&lt;SECTION&gt;</th>
</tr>
</thead>
<tbody id="results-body">
<tr>
<th>HTML</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML createElement</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>innerHTML</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML createElement</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via importNode</th>
<td class="fail">div</td>
<td class="pass">DIV</td>
<td class="fail">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via adoptNode</th>
<td class="fail">div</td>
<td class="pass">DIV</td>
<td class="fail">section</td>
<td class="pass">SECTION</td>
</tr>
</tbody>
</table>
<p>Internet Explorer fails in a different manner. To start, Internet Explorer doesn't support <code>importNode</code> or <code>adoptNode</code> so those particular tests simply don't run. However we can confirm that the case sensitivity of the unknown HTML 5 element is maintained in HTML, even though it shouldn't be.</p>
<p><TABLE id=results><THEAD><TR id=results-head><TH></TH><TH>&lt;div&gt;</TH><TH>&lt;DIV&gt;</TH><TH>&lt;section&gt;</TH><TH>&lt;SECTION&gt;</TH></TR></THEAD><TBODY id=results-body><TR><TH>HTML</TH><TD class=pass>DIV</TD><TD class=pass>DIV</TD><TD class=fail>section</TD><TD class=pass>SECTION</TD></TR><TR><TH>HTML createElement</TH><TD class=pass>DIV</TD><TD class=pass>DIV</TD><TD class=fail>section</TD><TD class=pass>SECTION</TD></TR><TR><TH>innerHTML</TH><TD class=pass>DIV</TD><TD class=pass>DIV</TD><TD class=fail>section</TD><TD class=pass>SECTION</TD></TR><TR><TH>XML</TH><TD class=pass>div</TD><TD class=pass>DIV</TD><TD class=pass>section</TD><TD class=pass>SECTION</TD></TR><TR><TH>XML createElement</TH><TD class=pass>div</TD><TD class=pass>DIV</TD><TD class=pass>section</TD><TD class=pass>SECTION</TD></TR><TR><TH>HTML via importNode</TH><TD class=error colSpan=4>Error: Object doesn't support this property or method</TD></TR><TR><TH>HTML via adoptNode</TH><TD class=error colSpan=4>Error: Object doesn't support this property or method</TD></TR></TBODY></TABLE></p>
<p>Opera ups the ante one further: Since it attempts to simultaneous follow web standards, and implement Internet Explorer's weird quirks, it <em>both</em> fails the <code>importNode</code>/<code>adoptNode</code> and the HTML 5 unknown element cases.</p>
<p><TABLE id="results"> <THEAD><TR id="results-head"><TH></TH><TH>&lt;div&gt;</TH><TH>&lt;DIV&gt;</TH><TH>&lt;section&gt;</TH><TH>&lt;SECTION&gt;</TH></TR></THEAD> <TBODY id="results-body"><TR><TH>HTML</TH><TD class="pass">DIV</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>HTML createElement</TH><TD class="pass">DIV</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>innerHTML</TH><TD class="pass">DIV</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>XML</TH><TD class="pass">div</TD><TD class="pass">DIV</TD><TD class="pass">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>XML createElement</TH><TD class="pass">div</TD><TD class="pass">DIV</TD><TD class="pass">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>HTML via importNode</TH><TD class="fail">div</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>HTML via adoptNode</TH><TD class="fail">div</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR></TBODY> </TABLE></p>
<p><strong><a href="http://ejohn.org/files/bugs/nodeName/xhtml.xhtml">XHTML (served with correct mimetype)</a></strong></p>
<p>Nearly every browser that supported showing this page (Firefox, Safari, Opera, Chrome) displayed the same, expected, results:</p>
<table id="results">
<thead>
<tr id="results-head">
<th/>
<th>&lt;div&gt;</th>
<th>&lt;DIV&gt;</th>
<th>&lt;section&gt;</th>
<th>&lt;SECTION&gt;</th>
</tr>
</thead>
<tbody id="results-body">
<tr>
<th>HTML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML createElement</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>innerHTML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML createElement</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via importNode</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via adoptNode</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
</tbody>
</table>
<p>An XHTML page served properly is just an XML document - thus the case of elements is sensitive (as to be expected).</p>
<p>... except in Opera. Opera apparently will treat div elements case insensitively, when injected using <code>.innerHTML</code>, even if it's being served within an XHTML document.</p>
<table id="results">
<thead>
<tr id="results-head">
<th/>
<th>&lt;div&gt;</th>
<th>&lt;DIV&gt;</th>
<th>&lt;section&gt;</th>
<th>&lt;SECTION&gt;</th>
</tr>
</thead>
<tbody id="results-body">
<tr>
<th>HTML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML createElement</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>innerHTML</th>
<td class="fail">DIV</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML createElement</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via importNode</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via adoptNode</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
</tbody>
</table>
<h3>Update: XHTML as XML Tests</h3>
<p>Based upon some suggestions in the comments I've run some additional tests. Namely I tested the loading of an XML document that has the correct XHTML namespace attached to it (specifically I used the same XHTML test page that I used for the other tests, just appending a .xml extension instead of .xhtml). The results are rather interesting - and promising, at least. (Note: Internet Explorer continues to fail as it doesn't have an adoptNode/importNode method.)</p>
<p>Firefox continues to fail the importing of XML nodes, even when they're coming  from an XML document:</p>
<table id="results">
<thead>
<tr id="results-head">
<th></th>
<th>&lt;div&gt;</th>
<th>&lt;DIV&gt;</th>
<th>&lt;section&gt;</th>
<th>&lt;SECTION&gt;</th>
</tr>
</thead>
<tbody id="results-body">
<tr>
<th>HTML</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML createElement</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>innerHTML</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML createElement</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via importNode</th>
<td class="fail">div</td>
<td class="pass">DIV</td>
<td class="fail">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via adoptNode</th>
<td class="fail">div</td>
<td class="pass">DIV</td>
<td class="fail">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML (XHTML)</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XHTML via importNode</th>
<td class="fail">div</td>
<td class="pass">DIV</td>
<td class="fail">section</td>
<td class="pass">SECTION</td>
</tr>
</tbody>
</table>
<p>As does Opera:</p>
<p><TABLE id="results"> <THEAD><TR id="results-head"><TH></TH><TH>&lt;div&gt;</TH><TH>&lt;DIV&gt;</TH><TH>&lt;section&gt;</TH><TH>&lt;SECTION&gt;</TH></TR></THEAD> <TBODY id="results-body"><TR><TH>HTML</TH><TD class="pass">DIV</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>HTML createElement</TH><TD class="pass">DIV</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>innerHTML</TH><TD class="pass">DIV</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>XML</TH><TD class="pass">div</TD><TD class="pass">DIV</TD><TD class="pass">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>XML createElement</TH><TD class="pass">div</TD><TD class="pass">DIV</TD><TD class="pass">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>HTML via importNode</TH><TD class="fail">div</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>HTML via adoptNode</TH><TD class="fail">div</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>XML (XHTML)</TH><TD class="pass">div</TD><TD class="pass">DIV</TD><TD class="pass">section</TD><TD class="pass">SECTION</TD></TR><TR><TH>XHTML via importNode</TH><TD class="fail">div</TD><TD class="pass">DIV</TD><TD class="fail">section</TD><TD class="pass">SECTION</TD></TR></TBODY> </TABLE></p>
<p>BUT both Safari and Chrome PASS on the importing of XHTML nodes, coming from an XML document:</p>
<table id="results">
<thead>
<tr id="results-head">
<th></th>
<th>&lt;div&gt;</th>
<th>&lt;DIV&gt;</th>
<th>&lt;section&gt;</th>
<th>&lt;SECTION&gt;</th>
</tr>
</thead>
<tbody id="results-body">
<tr>
<th>HTML</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML createElement</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>innerHTML</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML createElement</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via importNode</th>
<td class="fail">div</td>
<td class="pass">DIV</td>
<td class="fail">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>HTML via adoptNode</th>
<td class="fail">div</td>
<td class="pass">DIV</td>
<td class="fail">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XML (XHTML)</th>
<td class="pass">div</td>
<td class="pass">DIV</td>
<td class="pass">section</td>
<td class="pass">SECTION</td>
</tr>
<tr>
<th>XHTML via importNode</th>
<td class="pass">DIV</td>
<td class="pass">DIV</td>
<td class="pass">SECTION</td>
<td class="pass">SECTION</td>
</tr>
</tbody>
</table>
<div id="test">
<div></div>
<p><DIV></DIV><br />
<section></section>
<p><SECTION></SECTION></div>
<p>This, in particular, is great news. It means that, at least, one browser understands the concept of loading in external (X)HTML into an HTML document and having it continue to work. It's unfortunate that it doesn't work in all browsers, though.</p>
</div>
<h2>Conclusion</h2>
<p>What can we learn from all of this? Unfortunately it appears as if we can't really trust our "trusted" rules about <code>.nodeName</code> case sensitivity for HTML documents. XML documents are completely safe and work as expected. XHTML (served with the correct mimetype) documents are nearly safe, save for the one bizarre Opera bug.</p>
<p>How will this change the code that we write? In short we can no longer trust the case insensitive nature of HTML documents - we need to assume that BOTH HTML and XML documents will be serving their content in a case sensitive nature - especially as more people start to adopt HTML 5 elements in their pages and expect some level of support in older browsers. This means that a number of selectors and DOM methods will take a performance hit as we can no longer take a case insensitive shortcut in our codebases.</p>
<p>There are a few outstanding jQuery tickets that are the result of these issues cropping up and now that I know the reasoning behind why they're happening I can now strip out all the case-insensitive performance improvements from the codebase - which is really quite unfortunate but at least it'll behave more consistently. I continue to stand by thesis from my earlier talk about the DOM: <a href="http://ejohn.org/blog/the-dom-is-a-mess/">The DOM is a mess</a> and every DOM method and property is broken in some way, in some browser.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/s3oj7-1-iCY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/nodename-case-sensitivity/feed/</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
		<item>
		<title>Deep Tracing of Internet Explorer</title>
		<link>http://ejohn.org/blog/deep-tracing-of-internet-explorer/</link>
		<comments>http://ejohn.org/blog/deep-tracing-of-internet-explorer/#comments</comments>
		<pubDate>Tue, 17 Nov 2009 23:20:54 +0000</pubDate>
		<dc:creator>John Resig</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://ejohn.org/blog/deep-tracing-of-internet-explorer/</guid>
		<description><![CDATA[After reading a recent post by Steve Souders concerning a free tool called dynaTrace Ajax, I was intrigued. It claimed to provide full tracing analysis of Internet Explorer 6-8 (including JavaScript, rendering, and network traffic). Giving it a try I was very impressed. I tested against a few web sites but got the most interesting [...]]]></description>
			<content:encoded><![CDATA[<p>After reading a <a href="http://www.stevesouders.com/blog/2009/09/30/dynatrace-ajax-edition-tracing-js-performance/">recent post by Steve Souders</a> concerning a free tool called <a href="http://ajax.dynatrace.com/pages/">dynaTrace Ajax</a>, I was intrigued. It claimed to provide full tracing analysis of Internet Explorer 6-8 (including JavaScript, rendering, and network traffic). Giving it a try I was very impressed. I tested against a few web sites but got the most interesting results running against the JavaScript-heavy Gmail in Internet Explorer 8.</p>
<p>I typically don't write about most performance analysis tools because, frankly, most of them are quite bland and don't provide very interesting information or analysis. dynaTrace provides some information that I've never seen before - in any tool on any browser.</p>
<p>dynaTrace Ajax works by sticking low-level instrumentation into Internet Explorer when it launches, capturing any activity that occurs - and I mean virtually any activity that you can imagine. I noticed very little slow down when running the browser in tracing mode (although it's sometimes hard to tell, considering the browser). However all of the tracing is recorded and saved for later, making it easy to record sessions for later analysis.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4113481610/" title="dynaTrace Ajax by John Resig, on Flickr"><img src="http://farm3.static.flickr.com/2610/4113481610_dae16cf451.jpg" width="500" height="383" alt="dynaTrace Ajax" style="border:0;" /></a></center></p>
<p>Above is the result of a recorded session, logging in to Gmail, reading a mail, and logging back out again. All aspects of the session are saved: Network requests, JavaScript source, all DOM events, etc. I had a hard time finding information that wasn't saved by the tool.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4112713485/in/set-72157622701070617/"><img src="http://ejohn.org/files/dynatrace-gmail-timeline1.sm.png" style="border:0px;"/></a></center></p>
<p>This is the full timeline view of loading a single the Gmail inbox. All network traffic, JavaScript parsing and execution, browser events, and CPU load can be seen.</p>
<p>You can select a segment of the timeline and get a view that looks like the following:</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4113481610/in/set-72157622701070617/"><img src="http://ejohn.org/files/dynatrace-gmail1.sm.png" style="border:0px;"/></a></center></p>
<p>In the above you can see a clearer picture of the exact interactions happening. A phenomenal amount of inline JavaScript execution followed by page layout calculation coinciding with loading of some data over the network. You can mouse over the individual blocks on the timeline to get more information (such as if the JavaScript execute was the result of a timer or what Ajax requests were firing to cause the network traffic). Additionally you can click the blocks to dive in and take a deeper view of the trace.</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4113482048/in/set-72157622701070617/"><img src="http://ejohn.org/files/dynatrace-gmail-trace1.sm.png" style="border:0px;"/></a></center></p>
<p>Digging in to the execution of an XMLHttpRequest on a page we get to see some of the full execution stack trace - and this is where the tools starts to become really interesting. The tool is capable of tracing across JavaScript, through the native XMLHttpRequest, through the network request, and back to the handler that fires when the request is done. This is phenomenal. This is the first tool that I've seen that's capable of tracing through native methods to give you a picture of what activity triggers which actions and the complete ramifications of what happens (in both CPU usage and execution time).</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4113482048/in/set-72157622701070617/"><img src="http://ejohn.org/files/dynatrace-gmail-trace2.sm.png" style="border:0px;"/></a></center></p>
<p>Note that in the stack trace view you can click any piece of code and see its location anywhere inside the source code (and this even works after you've already closed the browser and have moved on - all source code is saved for later analysis).</p>
<p>While it's interesting to trace through code to look for problems the bigger question is usually: Where are slowdowns occurring? This is where the HotPath view comes into play:</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4113481910/in/set-72157622701070617/"><img src="http://ejohn.org/files/dynatrace-gmail-hotspot1.sm.png" style="border:0px;"/></a></center></p>
<p>This looks like a typical execution count view - like the one that you might see in Internet Explorer's built in tool or in Firebug - except for one important point: This view includes JavaScript parsing and layout rendering times. This is huge! No other tool provides information on how long it takes to parse all the JavaScript code on your site or how long it takes to do all the rendering. Clicking those entries allows you to see a breakdown of every time JavaScript was parsed or a layout was rendered - from which you can trace back to get even more information about what caused those actions. I don't want to seem too excited but I really am, this is just an incredible amount of information - and it gets even better:</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4113481976/in/set-72157622701070617/"><img src="http://ejohn.org/files/dynatrace-gmail-hotspot-dom1.sm.png" style="border:0px;"/></a></center></p>
<p>Not only can you see the execution count for your defined JavaScript methods but you can also see execution time for the built-in DOM methods! Wondering what native method calls are slowing down your application? Wonder no more. From the HotSpot view you can filter by DOM or regular JavaScript and see exactly where execution time is going and what methods are so slow.</p>
<p>dynaTrace provides an additional view, called PurePath that attempts to figure out problematic scripts:</p>
<p><center><a href="http://www.flickr.com/photos/jeresig/4112713569/in/set-72157622701070617/"><img src="http://ejohn.org/files/dynatrace-gmail-purepath1.sm.png" style="border:0px;"/></a></center></p>
<p>Just another way to try and get a full picture as to where your application is slowing down and what may be causing the problem.</p>
<p>In all I'm hugely impressed with this (free!) tool and am already using it to do more testing and performance analysis on my code. I don't think any browser has ever had a tool capable of this type of analysis, let alone Internet Explorer 6 and 7, which are still a very real part of any developer's workflow.</p>
<p>I chatted with some of the dynaTrace guys and asked them to add in memory profiling and to support more browsers. If they can provide this quality of instrumentation for CPU and execution time I hope they can do the same for memory usage, the next un-tapped realm of JavaScript performance analysis.</p>
<img src="http://feeds.feedburner.com/~r/JohnResig/~4/qX57H5GeoJo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ejohn.org/blog/deep-tracing-of-internet-explorer/feed/</wfw:commentRss>
		<slash:comments>141</slash:comments>
		</item>
	</channel>
</rss>

