Section 13.5. Execution of JavaScript Programs


13.5. Execution of JavaScript Programs

The previous sections discussed the mechanics of integrating JavaScript code into an HTML file. Now the following sections discuss exactly how and when that integrated JavaScript code is executed by the JavaScript interpreter.

13.5.1. Executing Scripts

JavaScript statements that appear between <script> and </script> tags are executed in the order that they appear in the script. When a file has more than one script, the scripts are executed in the order in which they appear (with the exception of scripts with the defer attribute, which IE executes out of order). The JavaScript code in <script> tags is executed as part of the document loading and parsing process.

Any <script> element that does not have a defer attribute may call the document.write( ) method (described in detail in Chapter 15). The text passed to this method is inserted into the document at the location of the scripts. When the script is finished executing, the HTML parser resumes parsing the document, starting with any text output by the script.

Scripts can appear in the <head> or the <body> of an HTML document. Scripts in the <head> typically define functions to be called by other code. They may also declare and initialize variables that other code will use. It is common for scripts in the <head> of a document to define a single function and then register that function as an onload event handler for later execution. It is legal, but uncommon, to call document.write( ) in the <head> of a document.

Scripts in the <body> of a document can do everything that scripts in the <head> can do. It is more common to see calls to document.write( ) in these scripts, however. Scripts in the <body> of a document may also (using techniques described in Chapter 15) access and manipulate document elements and document content that appear before the script. As described later in this chapter, however, document elements are not guaranteed to be available and stable when the scripts in the <body> are executed. If a script simply defines functions and variables to be used later and does not call document.write( ) or otherwise attempt to modify document content, convention dictates that it should appear in the <head> of the document instead of the <body>.

As previously mentioned, IE executes scripts with the defer attribute out of order. These scripts are run after all nondeferred scripts and after the document is fully parsed, but before the onload event handler is triggered.

13.5.2. The onload Event Handler

After the document is parsed, all scripts have run, and all auxiliary content (such as images) has loaded, the browser fires the onload event and runs any JavaScript code that has been registered with the Window object as an onload event handler. An onload handler can be registered by setting the onload attribute of the <body> tag. It is also possible (using techniques shown in Chapter 17) for separate modules of JavaScript code to register their own onload event handlers. When more than one onload handler is registered, the browser invokes all handlers, but there is no guarantee about the order in which they are invoked.

When the onload handler is triggered, the document is fully loaded and parsed, and any document element can be manipulated by JavaScript code. For this reason, JavaScript modules that modify document content typically contain a function to perform the modification and event-registration code that arranges for the function to be invoked when the document is fully loaded.

Because onload event handlers are invoked after document parsing is complete, they must not call document.write( ). Instead of appending to the current document, any such call would instead begin a new document and overwrite the current document before the user even had a chance to view it.

13.5.3. Event Handlers and JavaScript URLs

When document loading and parsing ends, the onload handler is triggered, and JavaScript execution enters its event-driven phase. During this phase, event handlers are executed asynchronously in response to user input such as mouse motion, mouse clicks, and key presses. JavaScript URLs may be invoked asynchronously during this phase as well, if, for example, the user clicks on a link whose HRef attribute uses the javascript: pseudoprotocol.

<script> elements are typically used to define functions, and event handlers are typically used to invoke those functions in response to user input. Event handlers can define functions, of course, but this is an uncommon (and not very useful) thing to do.

If an event handler calls document.write( ) on the document of which it is a part, it will overwrite that document and begin a new one. This is almost never what is intended, and, as a rule of thumb, event handlers should never call this method. Nor should they call functions that call this method. The exception, however, is in multiwindow applications in which an event handler in one window invokes the write( ) method of the document of a different window. (See Section 14.8. for more on multiwindow JavaScript applications.)

13.5.4. The onunload Event Handler

When the user navigates away from a web page, the browser triggers the onunload event handler, giving the JavaScript code on that page one final chance to run. You can define an onunload handler by setting the onunload attribute of the <body> tag or with other event-handler registration techniques described in Chapter 17.

The onunload event enables you to undo the effects of your onload handler or other scripts in your web page. For example, if your application opens up a secondary browser window, the onunload handler provides an opportunity to close that window when the user leaves your main page. The onunload handler should not run any time-consuming operation, nor should it pop up a dialog box. It exists simply to perform a quick cleanup operation; running it should not slow down or impede the user's transition to a new page.

13.5.5. The Window Object as Execution Context

All scripts, event handlers, and JavaScript URLs in a document share the same Window object as their global object. JavaScript variables and functions are nothing more than properties of the global object. This means that a function declared in one <script> can be invoked by the code in any subsequent <script>.

Since the onload event is not triggered until after all scripts have executed, every onload event handler has access to all functions defined and variables declared by all scripts in the document.

Whenever a new document is loaded into a window, the Window object for that window is restored to its default state: any properties and functions defined by a script in the previous document are deleted, and any of the standard system properties that may have been altered or overwritten are restored. Every document begins with a clean slate. Your scripts can rely on this; they will not inherit a corrupted environment from the previous document. This also means that any variables and functions your scripts define persist only until the document is replaced with a new one.

The properties of a Window object have the same lifetime as the document that contains the JavaScript code that defined those properties. A Window object itself has a longer lifetime; it exists as long as the window it represents exists. A reference to a Window object remains valid regardless of how many web pages the window loads and unloads. This is relevant only for web applications that use multiple windows or frames. In this case, JavaScript code in one window or frame may maintain a reference to another window or frame. That reference remains valid even if the other window or frame loads a new document.

13.5.6. Client-Side JavaScript Threading Model

The core JavaScript language does not contain any threading mechanism, and client-side JavaScript does not add any. Client-side JavaScript is (or behaves as if it is) single-threaded. Document parsing stops while scripts are loaded and executed, and web browsers stop responding to user input while event handlers are being executed.

Single-threaded execution makes for much simpler scripting: you can write code with the assurance that two event handlers will never run at the same time. You can manipulate document content knowing that no other thread is attempting to modify it at the same time.

Single-threaded execution also places a burden on JavaScript programmers: it means that JavaScript scripts and event handlers must not run for too long. If a script performs a computationally intensive task, it will introduce a delay into document loading, and the user will not see the document content until the script completes. If an event handler performs a computationally intensive task, the browser may become nonresponsive, possibly causing the user to think that it has crashed.[*]

[*] Some browsers, such as Firefox, guard against denial-of-service attacks and accidental infinite loops, and prompt the user if a script or event handler takes too long to run. This gives the user the chance to abort a runaway script.

If your application must perform enough computation to cause a noticeable delay, you should allow the document to load fully before performing that computation, and you should be sure to notify the user that computation is underway and that the browser is not hung. If it is possible to break your computation down into discrete subtasks, you can use methods such as setTimeout( ) and setInterval( ) (see Chapter 14) to run the subtasks in the background while updating a progress indicator that displays feedback to the user.

13.5.7. Manipulating the Document During Loading

While a document is being loaded and parsed, JavaScript code in a <script> element can insert content into the document with document.write( ). Other kinds of document manipulation, using DOM scripting techniques shown in Chapter 15, may or may not be allowed in <script> tags.

Most browsers seem to allow scripts to manipulate any document elements that appear before the <script> tag. Some JavaScript coders do this routinely. However, no standard requires it to work, and there is a persistent, if vague, belief among some experienced JavaScript coders that placing document manipulation code within <script> tags can cause problems (perhaps only occasionally, only with some browsers, or only when a document is reloaded or revisited with the browser's Back button).

The only consensus that exists in this gray area is that it is safe to manipulate the document once the onload event has been triggered, and this is what most JavaScript applications do: they use the onload handler to trigger all document modifications. I present a utility routine for registering onload event handlers in Example 17-7.

In documents that contain large images or many images, the main document may be parsed well before the images are loaded and the onload event is triggered. In this case, you might want to begin manipulating the document before the onload event. One technique (whose safety is debated) is to place the manipulation code at the end of the document. An IE-specific technique is to put the document manipulation code in a <script> that has both defer and src attributes. A Firefox-specific technique is to make the document-manipulation code an event handler for the undocumented DOMContentLoaded event, which is fired when the document is parsed but before external objects, such as images, are fully loaded.

Another gray area in the JavaScript execution model is the question of whether event handlers can be invoked before the document is fully loaded. Our discussion of the JavaScript execution model has so far concluded that all event handlers are always triggered after all scripts have been executed. While this typically happens, it is not required by any standard. If a document is very long or is being loaded over a slow network connection, the browser might partially render the document and allow the user to begin interacting with it (and triggering event handlers) before all scripts and onload handlers have run. If such an event handler invokes a function that is not yet defined, it will fail. (This is one reason to define all functions in scripts in the <head> of a document.) And if such an event handler attempts to manipulate a part of the document that has not yet been parsed, it will fail. This scenario is uncommon in practice, and it is not usually worth the extra coding effort required to aggressively protect against it.




JavaScript. The Definitive Guide
JavaScript: The Definitive Guide
ISBN: 0596101996
EAN: 2147483647
Year: 2004
Pages: 767

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net