Closure 编译器服务已弃用,并将被移除。请考虑改为在本地运行编译器。
概览
与 API 通信介绍了有关如何与 Closure Compiler 服务进行通信的基础知识,但仅阐述了如何使用该服务从单行 JavaScript 中移除注释。本教程介绍如何在更现实的开发场景中使用 Closure 编译器服务:处理整个 JavaScript 文件以显著减小大小。
本教程假定您对 JavaScript 和 HTTP 有基本的了解。虽然它使用 Python 脚本将 JavaScript 提交到 Closure Compiler 服务,但您无需了解 Python 即可遵循示例。
压缩文件
与 API 通信中的示例将一个 JavaScript 字符串作为命令行参数传递到我们的编译脚本。但是,这种方法不适用于实际大小的 JavaScript 程序,因为如果代码超过几行,JavaScript 字符串很快就会变得非常庞大。对于较大的程序,您可以使用 code_url
请求参数指定要处理的 JavaScript 文件的名称。除了 js_code
之外,您还可以使用 code_url
,也可以将其用于 js_code
。
例如,请参考以下 JavaScript 程序:
/** * A simple script for adding a list of notes to a page. The list diplays * the text of each note under its title. */ /** * Creates the DOM structure for a note and adds it to the document. */ function makeNoteDom(noteTitle, noteContent, noteContainer) { // Create DOM structure to represent the note. var headerElement = document.createElement('div'); var headerText = document.createTextNode(noteTitle); headerElement.appendChild(headerText); var contentElement = document.createElement('div'); var contentText = document.createTextNode(noteContent); contentElement.appendChild(contentText); var newNote = document.createElement('div'); newNote.appendChild(headerElement); newNote.appendChild(contentElement); // Add the note's DOM structure to the document. noteContainer.appendChild(newNote); } /** * Iterates over a list of note data objects and creates a DOM */ function makeNotes(data, noteContainer) { for (var i = 0; i < data.length; i++) { makeNoteDom(data[i].title, data[i].content, noteContainer); } } function main() { var noteData = [ {title: 'Note 1', content: 'Content of Note 1'}, {title: 'Note 2', content: 'Content of Note 2'}]; var noteListElement = document.getElementById('notes'); makeNotes(noteData, noteListElement); } main();
您可以将此程序作为文件更方便地作为 Closure 编译器服务传递给一个大字符串。请按照以下步骤使用该服务处理文件:
- 将 JavaScript 保存在文件中。
- 将文件设置为可通过网络访问(例如,将其上传到您的网络服务器)。
- 向 Closure Compiler 服务发出 POST 请求(如与 API 通信中所述),但对于
js_code
参数,请替换为code_url
参数。值code_url
必须是第 1 步中创建的 JavaScript 文件的网址。
例如,您可以在文件 tutorial2.js
中找到此示例的 JavaScript。如需使用 Closure Compiler Service API 处理此文件,请将 Python 程序从与 API 通信更改为使用 code_url
,如下所示:
#!/usr/bin/python2.4 import httplib, urllib, sys # Define the parameters for the POST request and encode them in # a URL-safe format. params = urllib.urlencode([ ('code_url', sys.argv[1]), # <--- This parameter has a new name! ('compilation_level', 'WHITESPACE_ONLY'), ('output_format', 'text'), ('output_info', 'compiled_code'), ]) # Always use the following value for the Content-type header. headers = { "Content-type": "application/x-www-form-urlencoded" } conn = httplib.HTTPSConnection('closure-compiler.appspot.com') conn.request('POST', '/compile', params, headers) response = conn.getresponse() data = response.read() print data conn.close()
注意:Windows 用户可能需要安装 Python 才能重现此示例。如需了解如何在 Windows 上安装和使用 Python,请参阅 Python Windows 常见问题解答。
使用以下命令将代码发送到 Closure Compiler 服务:
$ python compile.py https://closure-compiler.appspot.com/closure/compiler/samples/tutorial2.js
Closure Compiler 服务从 https://closure-compiler.appspot.com/closure/compiler/samples/tutorial2.js
检索文件,并在响应中返回压缩的 JavaScript。
如需将多个输出文件编译到一个输出文件中,请添加多个 code_url
参数,如下例所示:
params = urllib.urlencode([ # Multiple code_url parameters: ('code_url', 'http://yourserver.com/yourJsPart1.js'), ('code_url', 'http://yourserver.com/yourJsPart2.js'), ('compilation_level', 'WHITESPACE_ONLY'), ('output_format', 'text'), ('output_info', 'compiled_code'), ])
改善压缩效果
到目前为止,这些示例都使用 WHITESPACE_ONLY
的 compilation_level
,它只是剥离了注释和空格。借助 SIMPLE_OPTIMIZATIONS
压缩级别,您可以实现更高的压缩率。如需使用 SIMPLE_OPTIMIZATIONS
压缩,请将 compilation_level
参数更改为 SIMPLE_OPTIMIZATIONS
:
params = urllib.urlencode([ ('code_url', sys.argv[1]), ('compilation_level', 'SIMPLE_OPTIMIZATIONS'), # <--- This parameter has a new value! ('output_format', 'text'), ('output_info', 'compiled_code'), ])
然后像之前一样运行脚本:
$ python compile.py https://closure-compiler.appspot.com/closure/compiler/samples/tutorial2.js
输出应如下所示:
var GLOBAL_document=document,$$PROP_appendChild="appendChild";function makeNoteDom(a,b,c){var d=GLOBAL_document.createElement("div");a=GLOBAL_document.createTextNode(a);d[$$PROP_appendChild](a);a=GLOBAL_document.createElement("div");b=GLOBAL_document.createTextNode(b);a[$$PROP_appendChild](b);b=GLOBAL_document.createElement("div");b[$$PROP_appendChild](d);b[$$PROP_appendChild](a);c[$$PROP_appendChild](b)}function makeNotes(a,b){for(var c=0;c<a.length;c++)makeNoteDom(a[c].title,a[c].content,b)} function main(){var a=[{title:"Note 1",content:"Content of Note 1"},{title:"Note 2",content:"Content of Note 2"}],b=GLOBAL_document.getElementById("notes");makeNotes(a,b)}main();
此代码比源程序更难读,但更小。
代码有多小?
如果我们将请求参数中的 output_info
从 compiled_code
更改为 statistics
,就可以确切地看到我们节省了多少空间:
Original Size: 1372 Compressed Size: 677 Compilation Time: 0
新的 JavaScript 小于原始 JavaScript 的一半。
Closure 编译器服务是如何缩小程序的?
在此情况下,Closure 编译器通过重命名局部变量来实现大小缩减。例如,原始文件包含以下代码行:
var headerElement = document.createElement('div');
Closure Compiler 将此语句更改为:
var d=document.createElement("div");
Closure 编译器会将函数 makeNoteDom
中的符号 headerElement
更改为 d
,从而保留功能。但是,headerElement
的 13 个字符在显示时的三个位置已缩减为一个字符。这样可节省 36 个字符。
使用 SIMPLE_OPTIMIZATIONS
进行编译始终会保留语法上有效的 JavaScript 的功能,前提是代码不使用字符串名称(例如,使用 eval()
语句)访问局部变量。
后续操作
现在,您已经熟悉了 SIMPLE_OPTIMIZATIONS
和使用该服务的基本机制,下一步是了解 ADVANCED_OPTIMIZATIONS
编译级别。需要执行一些额外的步骤才能确保 JavaScript 在编译之前和之后的工作方式都相同,但会让 JavaScript 更小。请参阅高级编译和 Extern,了解 ADVANCED_OPTIMIZATIONS
。