High Performance JavaScript 读书笔记(一)
一.Loading and Execution
?? JavaScript performance in the browser is arguably the most important usability issue facing developers. The problem is complex because of the blocking nature of JavaScript, which is to say that nothing else can happen while JavaScript code is being executed.
??? In fact, most browsers use a single process for both user interface (UI) updates and JavaScript execution, so only one can happen at any given moment in time. The longer JavaScript takes to execute, the longer it takes before the browser is free to respond to user input.
??? On a basic level, this means that the very presence of a <script> tag is enough to make the page wait for the script to be parsed and executed. Whether the actual JavaScript code is inline with the tag or included in an external file is irrelevant; the page download and rendering must stop and wait for the script to complete before proceeding. This is a necessary part of the page’s life cycle because the script may cause changes to the page while executing. The typical example is using document.write() in the middle of a page (as often used by advertisements).
??? When the browser encounters a <script> tag, as in this HTML page, there is no way?of knowing whether the JavaScript will insert content into the <p>, introduce additional?elements, or perhaps even close the tag. Therefore, the browser stops processing the?page as it comes in, executes the JavaScript code, then continues parsing and rendering?the page. The same takes place for JavaScript loaded using the src attribute; the browser?must first download the code from the external file, which takes time, and then parse?and execute the code. Page rendering and user interaction are completely blocked during?this time.
?? Though this code seems innocuous, it actually has a severe performance issue: there are three JavaScript files being loaded in the <head>. Since each <script> tag blocks the page from continuing to render until it has fully downloaded and executed the JavaScript code, the perceived performance of this page will suffer. Keep in mind that browsers don’t start rendering anything on the page until the opening <body> tag is encountered. Putting scripts at the top of the page in this way typically leads to a noticeable delay, often in the form of a blank white page, before the user can even begin reading or otherwise interacting with the page.
??? Internet Explorer 8, Firefox 3.5, Safari 4, and Chrome 2 all allow parallel downloads?of JavaScript files. This is good news because the <script> tags don’t necessarily block?other <script> tags from downloading external resources. Unfortunately, JavaScript?downloads still block downloading of other resources, such as images. And even though?downloading a script doesn’t block other scripts from downloading, the page must still?wait for the JavaScript code to be downloaded and executed before continuing. So while?the latest browsers have improved performance by allowing parallel downloads, the?problem hasn’t been completely solved. Script blocking still remains a problem.
??? Because scripts block downloading of all resource types on the page, it’s recommended?to place all <script> tags as close to the bottom of the <body> tag as possible so as not?to affect the download of the entire page. For example:?? This code represents the recommended position for <script> tags in an HTML file.?Even though the script downloads will block one another, the rest of the page has?already been downloaded and displayed to the user so that the entire page isn’t perceived?as slow. This is the Yahoo! Exceptional Performance team’s first rule about?JavaScript: put scripts at the bottom.
Grouping Scripts
?? Since each <script> tag blocks the page from rendering during initial download, it’s helpful to limit the total number of <script> tags contained in the page. This applies to both inline scripts as well as those in external files. Every time a <script> tag is encountered during the parsing of an HTML page, there is going to be a delay while the code is executed; minimizing these delays improves the overall performance of the page.
?? The problem is slightly different when dealing with external JavaScript files. Each HTTP request brings with it additional performance overhead, so downloading one single 100 KB file will be faster than downloading four 25 KB files. To that end, it’s helpful to limit the number of external script files that your page references.?
???Typically, a large website or web application will have several required JavaScript files. You can minimize the performance impact by concatenating these files together into a single file and then calling that single file with a single <script> tag.
Nonblocking Scripts
?? JavaScript’s tendency to block browser processes, both HTTP requests and UI updates,is the most notable performance issue facing developers. Keeping JavaScript files small and limiting the number of HTTP requests are only the first steps in creating a responsive web application. The richer the functionality an application requires, the more JavaScript code is required, and so keeping source code small isn’t always an option.
?? Limiting yourself to downloading a single large JavaScript file will only result in locking the browser out for a long period of time, despite it being just one HTTP request. To get around this situation, you need to incrementally add more JavaScript to the page in a way that doesn’t block the browser.
?? The secret to nonblocking scripts is to load the JavaScript source code after the page has finished loading. In technical terms, this means downloading the code after the window’s load event has been fired. There are a few techniques for achieving this result.
Deferred Scripts
??? HTML 4 defines an additional attribute for the <script> tag called defer. The defer attribute indicates that the script contained within the element is not going to modify the DOM and therefore execution can be safely deferred until a later point in time. The defer attribute is supported only in Internet Explorer 4+ and Firefox 3.5+, making it less than ideal for a generic cross-browser solution. In other browsers, the defer attribute is simply ignored and so the <script> tag is treated in the default (blocking) manner. Still, this solution is useful if your target browsers support it. The following is an example usage:??? A <script> tag with defer may be placed anywhere in the document. The JavaScript file will begin downloading at the point that the <script> tag is parsed, but the code will not be executed until the DOM has been completely loaded (before the onload?event handler is called). When a deferred JavaScript file is downloaded, it doesn’t block?the browser’s other processes, and so these files can be downloaded in parallel with?others on the page.
?? Any <script> element marked with defer will not execute until after the DOM has been?completely loaded; this holds true for inline scripts as well as for external script files.?The following simple page demonstrates how the defer attribute alters the behavior of?scripts:?? ?In most cases, you’ll want to use a single approach to dynamically load JavaScript files.?The following function encapsulates both the standard and IE-specific functionality:?? You can dynamically load as many JavaScript files as necessary on a page, but make sure you consider the order in which files must be loaded. Of all the major browsers, only Firefox and Opera guarantee that the order of script execution will remain the same as you specify. Other browsers will download and execute the various code files in the order in which they are returned from the server. You can guarantee the order by chaining the downloads together, such as:?? Place this loading code just before the closing </body> tag. Doing so has several benefits. First, as discussed earlier, this ensures that JavaScript execution won’t prevent the rest of the page from being displayed. Second, when the second JavaScript file has finished downloading, all of the DOM necessary for the application has been created and is ready to be interacted with, avoiding the need to check for another event (such as window.onload) to know when the page is ready for initialization.