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
。