Background
I am working on a project that runs in an embedded web browser in a small device with limited resources. The browser itself is a bit dated and has limits to its capabilities (HTML 4.01†, W3C DOM Level 2†, JavaScript 1.4). I have no documentation on the browser, so what I do know comes from trial and error.
The point is to retrieve dynamic content from a server so that only a minimal amount of inflexible code needs to be embedded into the device running the web browser. The browser does not support the XMLHTTPRequest object, so AJAX is out. Working with I do have, I wrote a bit of test code to dynamically insert JavaScript.
† Minor portions of these standards not supported
EDIT
While I cannot actually confirm it, I believe that this site may list the DOM support for the embedded browser because I see “Mozilla/4.0 (compatible; EBSWebC 2.6; Windows NT 5.1)” as the user agent in the server log.
<html>
<head>
</head>
<body onload="init()">
<div id="root"></div>
<script type="text/javascript">
<!--
function init() {
// Add a div element to the page.
var div = document.createElement("div");
div.id = "testDiv";
document.getElementById("root").appendChild(div);
// Set a timeout to insert the JavaScript after 2 seconds.
setTimeout("dynamicJS()", 2000);
}
function dynamicJS() {
...
}
//-->
</script>
</body>
</html>
Method 1
I initially implemented the dynamicJS function using Method 1 and found that while the code executes as expected in Chrome, IE8, and FireFox 3.5, the JavaScript is not actually retrieved by the embedded browser when the element is appended.
function dynamicJS() {
var js = document.createElement("script");
js.type = "text/javascript";
js.src = "js/test.js";
document.getElementById("root").appendChild(js);
}
Method 2
Looking for a work around, I implemented Method 2. This method actually works in the embedded browser as the JavaScript is retrieved and executed, but it does not work in other modern web browsers’s I tested against (Chrome, IE8, FireFox 3.5).
function dynamicJS() {
var js= '<script type="text/javascript" src="js/test.js"> </s' + 'cript>';
document.getElementById("testDiv").innerHTML = js;
}
Question
I’m new to JavaScript and web programming in general, so I’m hoping one (or more) of the experts here can shed some light on this for me.
Is there anything technically wrong with Method 2 and if not, why doesn’t it work in modern web browsers?
The
innerHTMLproperty has not yet actually been standardized, though all modern browsers support it, and the draft standard of HTML5 includes a definition of how it should work. According to the HTML5 specification:innerHTMLwas first introduced in Microsoft Internet Explorer 4, and due to its popularity among authors, has been adopted by all of the other browsers, which is what led to its inclusion in HTML5. So, let’s check Microsoft’s documentation:So apparently, in IE you can get scripts inserted via
innerHTMLto execute, but only if you add adeferattribute (I do not have IE in front of me to test this).deferis another feature that was first added to IE; it was included in HTML 4.01, but not picked up by any of the other browsers for quite a while. HTML5 includes a much more detailed description of how<script defer>should work, though it appears to be slightly incompatible with how it works in IE, as it does not allow execution of scripts added viainnerHTML. The HTML5 definition of<script defer>appears to be implemented in Firefox 3.5 and Safari 4.In summary,
innerHTMLhasn’t really been standardized yet, but instead simply implemented by all of the browser vendors in slightly different ways. In IE, the original implementation, it didn’t support execution of scripts except with adeferattribute, anddeferhasn’t been supported in other browsers until just recently, and so the other browsers simply don’t support execution of scripts added usinginnerHTML. This behavior is what HTML5 is standardizing on, so unless Microsoft objects, is probably going to be what goes into the standard.It sounds like the browser you are working with didn’t do as good a job of implementing a compatible
innerHTML, as it executes scripts added usinginnerHTMLno matter what. This is unsurprising, as the behavior isn’t standardized and so needs to be either reverse engineered or gleaned from reading the documentation of other browsers (which may not have included this fact in the past). One of the main goals of HTML5 is to actually write down all of these unwritten assumptions and undocumented behaviors, so that in the future, someone implementing a browser can do so without being misled by a spec that doesn’t match reality, or without having to do the effort of reverse engineering the existing browsers.It looks to me that you may have to use Method 2 on your embedded browser, and Method 1 if you want to run on the common desktop browsers. It would probably be a good idea to try Method 1 first, and fall back to Method 2 if that does not work, and then error out (or silently fail, depending on your needs) if neither one works.