[翻译]High Performance JavaScript(028)

JavaScript Minification  JavaScript紧凑

 

    JavaScript minification is the process by which a JavaScript file is stripped of everything that does not contribute to its execution. This includes comments and unnecessary whitespace. The process typically reduces the file size by half, resulting in faster downloads, and encourages programmers to write better, more extensive inline documentation.

    JavaScript紧凑指的是剔除一个JavaScript文件中一切运行无关内容的过程。包括注释和不必要的空格。该处理通常可将文件尺寸缩减到一半,其结果是下载速度更快,并鼓励程序员写出更好,更详细的内联文档。

 

    JSMin (http://www.crockford.com/javascript/jsmin.html), developed by Douglas Crockford, remained the standard in JavaScript minification for a long time. However, as web applications kept growing in size and complexity, many felt it was time to push JavaScript minification a step further. This is the main reason behind the development of the YUI Compressor (http://developer.yahoo.com/yui/compressor/), a tool that performs all kinds of smart operations in order to offer a higher level of compaction than other tools in a completely safe way. In addition to stripping comments and unnecessary whitespace, the YUI Compressor offers the following features:

    JSMin(http://www.crockford.com/javascript/jsmin.html),由Douglas Crockford开发,它保持了JavaScript紧凑标准很长一段时间。然而随着网络应用程序在规模和复杂性上不断增长,许多人认为JavaScript紧凑应当再向前推进一步。这是开发YUI压缩器的主要原因(http://developer.yahoo.com/yui/compressor/)它提供了所有类型的智能操作,为了提供比其它工具更高级的紧凑操作并且以完全安全的方法实现。除了剔除注释和不必要的空格,YUI压缩器还提供以下功能:

 

• Replacement of local variable names with shorter (one-, two-, or three-character) variable names, picked to optimize gzip compression downstream

  将局部变量名替换以更短的形式(1个,2个,或3个字符),以优化后续的gzip压缩工作

 

• Replacement of bracket notation with dot notation whenever possible

(e.g., foo["bar"] becomes foo.bar)

  尽可能将中括号操作符替换为点操作符(例如foo:["bar"]变成foo.bar)

 

• Replacement of quoted literal property names whenever possible

(e.g., {"foo":"bar"} becomes {foo:"bar"})

  尽可能替换引号直接量属性名(例如{"foo":"bar"}变成{foo:"bar"})

 

• Replacement of escaped quotes in strings (e.g., 'aaa/'bbb' becomes "aaa'bbb")

  替换字符串中的转义引号(例如'aaa/'bbb'变成"aaa'bbb")

 

• Constant folding (e.g., "foo"+"bar" becomes "foobar")

  常量折叠(例如"foo"+"bar"变成"foobar")

 

    Running your JavaScript code through the YUI Compressor results in tremendous savings compared to JSMin without any further action. Consider the following numbers on the core files of the YUI library (version 2.7.0, available at http://developer.yahoo.com/yui/):

    与JSMin相比,通过YUI压缩器极大节省了您的JavaScript代码而无需更多操作。下面的数字是YUI库的核心代码(2.7.0版,下载地址:http://developer.yahoo.com/yui/):

 

Raw yahoo.js, dom.js and event.js                     192,164 bytes
yahoo.js, dom.js and event.js + JSMin                 47,316 bytes
yahoo.js, dom.js and event.js + YUI Compressor 35,896 bytes

 

    In this example, the YUI Compressor offers 24% savings out of the box compared to JSMin. However, there are things you can do to increase the byte savings even further. Storing local references to objects/values, wrapping code in a closure, using constants for repeated values, and avoiding eval (and its relatives, the Function constructor, setTimeout, and setInterval when used with a string literal as the first argument), the with keyword, and JScript conditional comments all contribute to making the minified file smaller. Consider the following function, designed to toggle the selected class on the specified DOM element (220 bytes):

    在这个例子中,YUI压缩器与JSMin相比节省了24%空间。然而,你还可以进一步节省空间。将局部引用存储在对象/值中,用闭包封装代码,使用常量替代重复值,避免eval(以及相似的Function构造器,setTimeout和setInterval使用字符串直接量作为第一个参数),with关键字,JScript条件注释,都有助于进一步精缩文件。考虑下面的函数,用来转换特定DOM元素的selected类(220字节):

 

function toggle (element) {
  if (YAHOO.util.Dom.hasClass(element, "selected")){
    YAHOO.util.Dom.removeClass(element, "selected");
  } else {
    YAHOO.util.Dom.addClass(element, "selected");
  }
}

    The YUI Compressor will transform this code into the following (147 bytes):

    YUI压缩器将此代码转换如下(147字节):

 

function toggle(a){if(YAHOO.util.Dom.hasClass(a,"selected")){YAHOO.util.Dom.removeClass(a,"selected")}else{YAHOO.util.Dom.addClass(a,"selected")}};

    If you refactor the original version by storing a local reference to YAHOO.util.Dom and using a constant for the "selected" value, the code becomes (232 bytes):

    如果你重构原始代码,将YAHOO.util.Dom存入一个局部引用,并使用常量存放"select"值,代码将变成如下的样子(232字节):

 

function toggle (element) {
  var YUD = YAHOO.util.Dom, className = "selected";
  if (YUD.hasClass(element, className)){
    YUD.removeClass(element, className);
  } else {
    YUD.addClass(element, className);
  }
}

    This version shows even greater savings after minification using the YUI Compressor (115 bytes):

    此版本在经过YUI压缩器紧凑处理之后将变得更小(115字节):

 

function toggle(a){var c=YAHOO.util.Dom,b="selected";if(c.hasClass(a,b)){c.removeClass(a,b)}else{c.addClass(a,b)}};

    The compaction ratio went from 33% to 48%, which is a staggering result given the small amount of work needed. However, it is important to note that gzip compression, happening downstream, may yield conflicting results; in other words, the smallest minified file may not always give the smallest gzipped file. That strange result is a direct consequence of lowering the amount of redundancy in the original file. In addition, this kind of microoptimization incurs a small runtime cost because variables are now used in place of literal values, thus requiring additional lookups. Therefore, I usually recommend not abusing these techniques, although it may still be worth considering them when serving content to user agents that don't support (or advertise their support for) gzip compression.

    压缩率从33%变为48%,只需要少量工作就得到惊人的结果。然而,要注意后续的gzip压缩,可能会产生相反的结果。换句话说,最小的紧凑文件并不总是给出最小的gzip压缩文件。这种奇怪的结果是降低原文件的冗余量造成的。此外,这类微观优化还导致了一个很小的运行期负担,因为变量替代了直接量,所以需要额外的查找。因此,通常建议不要滥用这些技术,虽然从服务内容到用户代理不支持(或声称支持)gzip压缩时,它们还是值得考虑的。

 

    In November 2009, Google released an even more advanced minification tool called the Closure Compiler (http://code.google.com/closure/compiler/). This new tool goes further than the YUI Compressor when using its advanced optimizations option. In this mode, the Closure Compiler is extremely aggressive in the ways that it transforms code and renames symbols. Although it yields incredible savings, it requires the developer to be very careful and to ensure that the output code works the same way as the input code. It also makes debugging more difficult because almost all of the symbols are renamed. The Closure library does come with a Firebug extension, named the
Closure Inspector (http://code.google.com/closure/compiler/docs/inspector.html), that provides a mapping between the obfuscated symbols and the original symbols. Nevertheless, this extension is not available on browsers other than Firefox, which may be a problem when debugging browser-specific code paths, and debugging still remains harder than with other, less aggressive minification tools.

    2009年11月,Google发布了一个更先进的紧凑工具闭包编译器http://code.google.com/closure/compiler/这种工具比YUI压缩器更进一步,当使用其先进优化选项时。在这种模式下,闭包编译器以极端霸道的方式转换代码并修改符号名。虽然它产生了难以置信的压缩率,但它要求开发者必须非常小心以确保输出代码与输入代码等价。它还使得调试更为困难,因为几乎所有符号都被改名了。此闭包库以一个Firebug扩展的形式发布,命名为闭包察看器(Closure Inspector)(http://code.google.com/closure/compiler/docs/inspector.html),并提供了一个转换后符号名和原始符号名之间的对照表。不过,这个扩展不能用于Firefox之外的浏览器,所以对那些浏览器相关的代码来说是个问题,而且和那些不这么霸道的紧凑工具相比,调试工作更困难。

 

Buildtime Versus Runtime Build Processes  开发过程中的编译时和运行时

 

    Concatenation, preprocessing, and minification are steps that can take place either at buildtime or at runtime. Runtime build processes are very useful during development, but generally are not recommended in a production environment for scalability reasons. As a general rule for building high-performance applications, everything that can be done at buildtime should not be done at runtime.

    连接,预处理,和紧凑既可以在编译时发生,也可以在运行时发生。在开发过程中,运行时创建过程非常有用,但由于扩展性原因一般不建议在产品环境中使用。开发高性能应用程序的一个普遍规则是,只要能够在编译时完成的工作,就不要在运行时去做。

 

    Whereas Apache Ant is definitely an offline build program, the agile build tool presented toward the end of this chapter represents a middle ground whereby the same tool can be used during development and to create the final assets that will be used in a production environment.

    Apache Ant无疑是一种脱机开发程序,而本章末尾出现的灵巧开发工具代表了中间路线,同样的工具即可用于开发期创建最终断言,也可用于产品环境。

 

JavaScript Compression  JavaScript压缩

 

    When a web browser requests a resource, it usually sends an Accept-Encoding HTTP header (starting with HTTP/1.1) to let the web server know what kinds of encoding transformations it supports. This information is primarily used to allow a document to be compressed, enabling faster downloads and therefore a better user experience. Possible values for the Accept-Encoding value tokens include: gzip, compress, deflate, and identity (these values are registered by the Internet Assigned Numbers Authority, or IANA).

    当网页浏览器请求一个资源时,它通常发送一个Accept-Encoding的HTTP头(以HTTP/1.1开始)让网页服务器知道传输所支持的编码类型。此信息主要用于允许文档压缩以获得更快下载速度,从而改善用户体验。Accept-Encoding的取值范围是:gzip,compress,deflate,和identity(这些值已经在以太网地址分配机构(即IANA)注册)。

 

    If the web server sees this header in the request, it will choose the most appropriate encoding method and notify the web browser of its decision via the Content-Encoding HTTP header.

    如果网页服务器在请求报文中看到这些信息头,它将选择适当的编码方法,并通过Content-Encoding的HTTP头通知浏览器。

 

    gzip is by far the most popular encoding. It generally reduces the size of the payload by 70%, making it a weapon of choice for improving the performance of a web application. Note that gzip compression should be used primarily on text responses, including JavaScript files. Other file types, such as images or PDF files, should not be gzipped, because they are already compressed and trying to compress them again is a waste of server resources.

    gzip大概是目前最流行的编码格式。它通常可将有效载荷减少到70%,成为提高网页应用性能的有力武器。注意gzip压缩器主要用于文本报文,包括JavaScript文件。其他文件类型,如图片和PDF文件,不应该使用gzip压缩,因为它们已经压缩,如果试图再次压缩只会浪费服务器资源。

 

    If you use the Apache web server (by far the most popular), enabling gzip compression requires installing and configuring either the mod_gzip module (for Apache 1.3 and available at http://www.schroepl.net/projekte/mod_gzip/) or the mod_deflate module (for Apache 2).

    如果您使用Apache网页服务器(目前最流行的),启用gzip压缩功能需要安装并配置mod_gzip模块(针对Apache 1.3,位于http://www.schroepl.net/projekte/mod_gzip/)或者mod_deflate模块(针对Apache 2)。

 

    Recent studies done independently by Yahoo! Search and Google have shown that roughly 15% of the content delivered by large websites in the United States is served uncompressed. This is mostly due to a missing Accept-Encoding HTTP header in the request, stripped by some corporate proxies, firewalls, or even PC security software. Although gzip compression is an amazing tool for web developers, one must be mindful of this fact and strive to write code as concisely as possible. Another technique is to serve alternate JavaScript content to users who are not going to benefit from gzip compression but could benefit from a lighter experience (although users should be given the choice to switch back to the full version).

    由Yahoo!搜索和Google独立完成的最新研究表明,美国大型网站提供的内容中有大约15%未经过压缩。大多数因为在请求报文中缺少Accept-Encoding的HTTP头,它被一些公司代理、防火墙、甚至PC安全软件剔除了。虽然gzip压缩是一个惊人的网页开发工具,但还是要注意到这个事实,尽量书写简洁的代码。另一种技术是提供替代的JavaScript内容,使那些不能受益于gzip压缩的用户,可以使用更简单的用户体验(用户可以选择切换回完整版本)。

 

    To that effect, it is worth mentioning Packer (http://dean.edwards.name/packer/), a JavaScript minifier developed by Dean Edwards. Packer is able to shrink JavaScript files beyond what the YUI Compressor can do. Consider the following results on the jQuery library (version 1.3.2, available at http://www.jquery.com/):

    为此,值得提到Packer (http://dean.edwards.name/packer/),由Dean Edwards开发的一个JavaScript紧凑工具。Packer对JavaScript压缩能够超过YUI压缩器的水平。考虑下面对jQuery库的压缩结果(版本1.3.2,下载地址http://www.jquery.com/):

 

jQuery                               120,180 bytes
jQuery + YUI Compressor              56,814 bytes
jQuery + Packer                 39,351 bytes
Raw jQuery + gzip                    34,987 bytes
jQuery + YUI Compressor + gzip  19,457 bytes
jQuery + Packer + gzip          19,228 bytes

 

    After gzipping, running the jQuery library through Packer or the YUI Compressor yields very similar results. However, files compressed using Packer incur a fixed runtime cost (about 200 to 300 milliseconds on my modern laptop). Therefore, using the YUI Compressor in combination with gzipping always gives the best results. However, Packer can be used with some success for users on slow lines that don't support gzip compression, for whom the cost of unpacking is negligible compared to the cost of downloading large amounts of code. The only downside to serving different JavaScript content to different users is increased QA costs.

    经过gzip压缩之后,jQuery库经过Packer或YUI压缩器产生的结果非常相近。然而,使用Packer压缩文件导致一个固定的运行时代价(在我的不落后的笔记本电脑上大约是200至300毫秒)。因此,使用YUI压缩器和gzip结合总能给出最佳结果。然而,Packer可用于网速不高或者不支持gzip压缩的情况,解压缩的代价与下载大量代码的代价相比微不足道。为不同用户提供不同JavaScript的唯一缺点是质量保证成本的增加。

 

Caching JavaScript Files  缓存JavaScript文件

 

    Making HTTP components cacheable will greatly improve the experience of repeat visitors to your website. As a concrete example, loading the Yahoo! home page (http://www.yahoo.com/) with a full cache requires 90% fewer HTTP requests and 83% fewer bytes to download than with an empty cache. The round-trip time (the elapsed time between the moment a page is requested and the firing of the onload event) goes from 2.4 seconds to 0.9 seconds (http://yuiblog.com/blog/2007/01/04/performance-research-part-2/). Although caching is most often used on images, it should be used on all static components, including JavaScript files.

    使HTTP组件可缓存将大大提高用户再次访问网站时的用户体验。一个具体的例子是,加载Yahoo!主页时(http://www.yahoo.com/),和不使用缓存相比,使用缓存将减少90%的HTTP请求和83%的下载字节。往返时间(从请求页面开始到第一次onload事件)从2.4秒下降到0.9秒(http://yuiblog.com/blog/2007/01/04/performance-research-part-2/)。虽然图片经常使用缓存,但它应当被使用在所有静态内容上,包括JavaScript文件。

 

    Web servers use the Expires HTTP response header to let clients know how long a resource can be cached. The format is an absolute timestamp in RFC 1123 format. An example of its use is: Expires: Thu, 01 Dec 1994 16:00:00 GMT. To mark a response as "never expires," a web server sends an Expires date approximately one year in the future from the time at which the response is sent. Web servers should never send Expires dates more than one year in the future according to the HTTP 1.1 RFC (RFC 2616, section 14.21).

    网页服务器使用Expires响应报文HTTP头让客户端知道缓存资源的时间。它是一个RFC 1123格式的绝对时间戳。例如:Expires: Thu, 01 Dec 1994 16:00:00 GMT。要将响应报文标记为“永不过期”,网页服务器可以发送一个时间为请求时间之后一年的Expires数据。根据HTTP 1.1 RFC(RFC 2616,14.21节)的要求,网页服务器发送的Expires时间不应超过一年。

 

    If you use the Apache web server, the ExpiresDefault directive allows you to set an expiration date relative to the current date. The following example applies this directive to images, JavaScript files, and CSS stylesheets:

    如果你使用Apache网页服务器,ExpiresDefault指令允许你根据当前时间设置过期时间。下面的例子将此指令用于图片,JavaScript文件,和CSS样式表:

 

<FilesMatch "/.(jpg|jpeg|png|gif|js|css|htm|html)$">
  ExpiresActive on
  ExpiresDefault "access plus 1 year"
</FilesMatch>

    Some web browsers, especially when running on mobile devices, may have limited caching capabilities. For example, the Safari web browser on the iPhone does not cache a component if its size is greater than 25KB uncompressed (see http://yuiblog.com/blog/2008/02/06/iphone-cacheability/) or 15KB for the iPhone 3.0 OS. In those cases, it is relevant to consider a trade-off between the number of HTTP components and their cacheability by splitting them into smaller chunks.

    某些网页浏览器,特别是那些移动设备上的浏览器,可能有缓存限制。例如,iPhone的Safari浏览器不能缓存解压后大于25K的组件(见http://yuiblog.com/blog/2008/02/06/iphone-cacheability/),在iPhone 3.0操作系统上不能大于15K。在这种情况下,应衡量HTTP组件数量和它们的可缓存性,考虑将它们分解成更小的块。

 

    You can also consider using client-side storage mechanisms if they are available, in which case the JavaScript code must itself handle the expiration.

    如果可能的话,你还可以考虑客户端存储机制,让JavaScript代码自己来处理过期。

 

    Finally, another technique is the use of the HTML 5 offline application cache, implemented in Firefox 3.5, Safari 4.0, and on the iPhone beginning with iPhone OS 2.1. This technology relies on a manifest file listing the resources to be cached. The manifest file is declared by adding a manifest attribute to the <html> tag (note the use of the HTML 5 DOCTYPE):

    最后,另一种技术是使用HTML 5离线应用程序缓存,它已经在如下浏览器中实现:Firefox 3.5,Safari 4.0,从iPhone OS 2.1开始以后的版本。此技术依赖于一个配置文件,列出应当被缓存的资源。此配置文件通过<html>标签的manifest属性(注意要使用HTML 5的DOCTYPE):

 

<!DOCTYPE html>
<html manifest="demo.manifest">

    The manifest file uses a special syntax to list offline resources and must be served using the text/cache-manifest mime type. More information on offline web application caching can be found on the W3C website at http://www.w3.org/TR/html5/offline.html.

    此配置文件使用特殊语法列出离线资源,必须使用text/cache-manifest指出它的媒体类型。更多关于离线网页应用缓存的信息参见W3C的网站http://www.w3.org/TR/html5/offline.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值