<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Everything old is new again &#187; debugger</title>
	<atom:link href="http://www.svendtofte.com/tag/debugger/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.svendtofte.com</link>
	<description>rantings &#38; scraps on code and web development</description>
	<lastBuildDate>Thu, 27 Aug 2009 22:38:34 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Javascript ghost debugging</title>
		<link>http://www.svendtofte.com/javascript/javascript-ghost-debugging/</link>
		<comments>http://www.svendtofte.com/javascript/javascript-ghost-debugging/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 00:46:35 +0000</pubDate>
		<dc:creator>Svend</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[debugger]]></category>

		<guid isPermaLink="false">http://www.svendtofte.com/?p=262</guid>
		<description><![CDATA[
Recently, I tried to use jQuery, as a way of dynamically loading all the scripts that a certain page requires. Instead of utilizing script tags in the header section, using a simple $.getScript("script.js"); loads the same code, what&#8217;s more, this code is loaded asynchronously, which helps improve loading performance. The only problem is that loading [...]]]></description>
			<content:encoded><![CDATA[<div style="float:right;"><img src="/wp-content/uploads/2009/07/mario-boo.jpg" alt="Boo"></div>
<p>Recently, I tried to use jQuery, as a way of dynamically loading all the scripts that a certain page requires. Instead of utilizing script tags in the header section, using a simple <code>$.getScript("script.js");</code> loads the same code, what&#8217;s more, this code is loaded asynchronously, which helps <a href="http://www.stevesouders.com/blog/2008/12/27/coupling-async-scripts /">improve loading performance</a>. The only problem is that loading scripts this way, makes them <em>unavailable for debugging</em>.</p>
<p>Debugging dynamically included script files presents some special challenges on it&#8217;s own. The primary being that that the web is basicly not a structured enviroment, like a folder on disk, and references to files and/or code is can be very intermittent.</p>
<p><span id="more-262"></span></p>
<h3>Some methods for loading remote code</h3>
<p>Here&#8217;s just some of the many ways that code may be included dynamically in a page (these are just rough outlines, buyer beware.) Be especially wary that this code is specifically for loading scripts, if you want to load JSON, you&#8217;ll need a different approach, just spilling your guts in the global scope is quite messy.</p>
<ol>
<li>
<p>Using XMLHttpRequest to load the script, and then insert via DOM methods into the page itself.</p>
<pre>
var req = new XMLHttpRequest();
req.open('GET', 'delayed.js', true)
req.onreadystatechange = function(e) {
    var head= document.getElementsByTagName('body')[0];
    var delayed = document.createElement('script');
    var txt = document.createTextNode(req.responseText);
    delayed.appendChild(txt);
    head.appendChild(delayed);
}
req.send();
</pre>
</li>
<li>
<p>Using XMLHttpRequest to load the script, and then use <code>eval</code> to execute the code in the global scope.</p>
<pre>
var req = new XMLHttpRequest();
req.open('GET', 'delayed.js', true)
req.onreadystatechange = function(e) {
    eval(req.responseText);
}
req.send();
</pre>
</li>
<li>
<p>Dynamically create a script tag with DOM methods, and then point it&#8217;s <code>src</code> attribute to the script you wish download.</p>
<pre>
var head= document.getElementsByTagName('head')[0];
var delayed = document.createElement('script');
delayed.onreadystatechange = function() {
    if (delayed.readyState == "loaded" ||
        delayed.readyState == "complete") delay();
}
delayed.src = "delayed.js";
head.appendChild(delayed);
</pre>
<p>This code also details how you can get a callback for when the actual script has loaded, so you&#8217;re not &#8220;missing&#8221; out on the callback functionality of XMLHttpRequest.</p>
</li>
</ol>
<p>jQuery basicly executes the first approach. The little twist is that just after the script has been added to the browser, it removes the tag again, so it&#8217;s not &#8220;littering&#8221; the document DOM with these script tags the author himself didn&#8217;t insert. This can be seen in the jQuery script at around line 646, where you find the <code>globalEval</code> function (assuming the development version, not the minified versions.)</p>
<h3>The problem with anonymous code</h3>
<p>This is all dandy, the problem simply is that no debuggers expose the anonymous code which enters the global scope in this fashion.</p>
<p class="imgWithCaption"><img src="http://www.svendtofte.com/wp-content/uploads/2009/07/firebug-html-view.gif" alt="Firebug showing a webpage with a static and dynamic node of Javascript" /><br /> Firebug showing a webpage with both a static and a dynamically loaded script (the script was loaded with jQuery, but with a modified jQuery so that it leaves the node in the DOM). Everything looks fine.</p>
<p class="imgWithCaption"><img src="http://www.svendtofte.com/wp-content/uploads/2009/07/firebug-js-view.gif" alt="Firebug's Javascript tab with only the static node available for debugging." /><br /> Firebug&#8217;s script tab shows a different view, namely the one where the dynamically loaded script block is gone, and thus not available for debugging.  </p>
<p>If you try to load the following script, with this piece of jQuery, <code>$.getScript("delay.js", function() { delay(); });</code>, will lead the debugger to exclaim that the method name is &#8220;anonymous&#8221;!</p>
<pre>
function delay() {
    alert("hello from delayed.js");
    console.trace();
}
</pre>
<h3>Loading code for proper debugging</h3>
<p>As you can see, the way that jQuery (and many other libs) chooses to load their scripts is a rather high-tech one, and the solution is as simple as not using XMLHttpRequest. By utilizing the third method of remotely loading scripts, allows you to morely accurately debug the scripts.</p>
<p>Take the following page and two script files for instance:</p>
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;script type="text/javascript"&gt;
function load(scriptSrc, callback) {
    var head= document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.onreadystatechange = function() {
        if (script.readyState == "loaded" ||
            script.readyState == "complete") callback();
    }
    script.src = scriptSrc;
    head.appendChild(script);
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;&lt;a href="javascript:load('load1.js',function() { load1(); });"&gt;load 1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="javascript:load('load2.js',function() { load2(); });"&gt;load 1&lt;/a&gt;&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<pre>
function load1() {
    alert("hello from load1");
}
</pre>
<pre>
function load2() {
    alert("hello from load2");
}
</pre>
<p>If we look at IE8&#8217;s Developer Tools JS debugger, you&#8217;ll notice that on page load, the scripts drop-down does not contain neither load1.js or load2.js.</p>
<p class="imgWithCaption"><img src="/wp-content/uploads/2009/07/ie-dev-tools-initial.gif" width="535" height="198" alt="IE8 Developer Tools on initial page load" /><br /> IE8&#8217;s Developer Tools on initial loading of a simple HTML page.</p>
<p>If we try to click the links however, the scripts we load will appear in the  dropdown, and allow easy debugging.</p>
<p class="imgWithCaption"><img src="/wp-content/uploads/2009/07/ie-dev-tools-loaded.gif" alt="IE8 Developer tools showing script available for debugging." width="535" height="198" /><br />IE8&#8217;s Developer Tools after having clicked the load link, the loaded script is now available for easy debugging (this works just as well in Firebug btw.)</p>
<h3>Debuggers</h3>
<p>Debuggers are still lacking behind in this area, compared to debuggers operating in more stable enviroments. There&#8217;s no denying that the web presents unique challenges, but the fact remains that the code is available for execution, but is not exposed for debugging. So while JS debuggers has moved forward since the days of <a href="/code/learning_venkman">Venkman</a>, I think there&#8217;s still ways to improve (and this need will become more pronounced as the dynamic nature of the web increases with time).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.svendtofte.com/javascript/javascript-ghost-debugging/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
