高性能javascript

150
High Performance JavaScript 2011-09-09 11年9月13日星期二

Upload: fangdeng

Post on 20-Jun-2015

825 views

Category:

Education


9 download

TRANSCRIPT

Page 1: 高性能Javascript

High � Performance � JavaScript2011-09-09

11年9月13日星期二

Page 2: 高性能Javascript

About � Me

谢传贵(阿贵)

前端开发部-前端架构组

新浪微薄@十月光风

11年9月13日星期二

Page 3: 高性能Javascript

11年9月13日星期二

Page 4: 高性能Javascript

先来看一场微电影,时长6.5s

11年9月13日星期二

Page 5: 高性能Javascript

0s

11年9月13日星期二

Page 6: 高性能Javascript

0.5s

11年9月13日星期二

Page 7: 高性能Javascript

1.0s

11年9月13日星期二

Page 8: 高性能Javascript

1.5s

11年9月13日星期二

Page 9: 高性能Javascript

2.0s

11年9月13日星期二

Page 10: 高性能Javascript

2.5s

11年9月13日星期二

Page 11: 高性能Javascript

3.0s

11年9月13日星期二

Page 12: 高性能Javascript

3.5s

11年9月13日星期二

Page 13: 高性能Javascript

4.0s

11年9月13日星期二

Page 14: 高性能Javascript

4.5s

11年9月13日星期二

Page 15: 高性能Javascript

5.0s

11年9月13日星期二

Page 16: 高性能Javascript

5.5s

11年9月13日星期二

Page 17: 高性能Javascript

6.0s

11年9月13日星期二

Page 18: 高性能Javascript

6.5s

11年9月13日星期二

Page 19: 高性能Javascript

0.0 0.5 1.0 1.5

2.0 2.5 3.0 3.5

4.0 4.5

6.5

5.55.0

6.0

回顾

11年9月13日星期二

Page 20: 高性能Javascript

知己知彼,百战不殆

11年9月13日星期二

Page 21: 高性能Javascript

Topic

JavaScript运行过程

快速响应UI

更多编程实践

效率相关的工具

11年9月13日星期二

Page 22: 高性能Javascript

JavaScript运行的过程是怎么样的?

11年9月13日星期二

Page 23: 高性能Javascript

解释(interpreted)

编译(compiled)

从源码到可执行代码

11年9月13日星期二

Page 24: 高性能Javascript

(function(){alert(‘hello � world’)

})

0100100101010101

Runtime.exec(‘hello.exe’)

source.js(源码)

helloworld.exe(二进制码)

运行时环境

编译

编译

执行

11年9月13日星期二

Page 25: 高性能Javascript

(function(){alert(‘hello � world’)

})

Runtime.exec(‘hello.exe’)

source.js(源码)

helloworld.exe(二进制码)

运行时环境

解释

编译&运行

11年9月13日星期二

Page 26: 高性能Javascript

(function(){alert(‘hello � world’)

})

Runtime.exec(‘中间机器

解释

编译&运行

运行时环境(浏览器)解释器执行伪代码

11年9月13日星期二

Page 27: 高性能Javascript

(function(){alert(‘hello � world’)

})

Runtime.exec(‘中间机器

解释

编译&运行

运行时环境(浏览器)

JavaScript � Engine

11年9月13日星期二

Page 28: 高性能Javascript

JavaScript � 是解释型语言

11年9月13日星期二

Page 29: 高性能Javascript

JavaScript代码执行的过程

词法分析

语法分析

预编译

运行

语法检查

运行时

11年9月13日星期二

Page 30: 高性能Javascript

JavaScript代码执行的过程

词法分析

语法分析

预编译

运行

语法检查

运行时

将上下文中var申明 � 的变量放入”栈”中 � 并赋值为undefined

读入”定义”的函数

11年9月13日星期二

Page 31: 高性能Javascript

看个例子

11年9月13日星期二

Page 32: 高性能Javascript

(function(){alert(a); � // � 会报错么?if(false){

var � a=1; � }

})();

11年9月13日星期二

Page 33: 高性能Javascript

函数执行前,函数内部变量均被声明(function(){

alert(a); � // � 显示undefined,不报错if(false){

var � a=1; � //不会执行到,亦被声明}

})();

11年9月13日星期二

Page 34: 高性能Javascript

再来看个例子

11年9月13日星期二

Page 35: 高性能Javascript

test();function � test(){ �  alert(1);}test();function � test(){ �  alert(2);}test();var � test � = � function(){ �  alert(3);}test();test � = � function(){ �  alert(4);}test();

11年9月13日星期二

Page 36: 高性能Javascript

test();function � test(){//预编译定义,运行时略过 �  alert(1);}test();function � test(){//预编译定义,运行时略过 �  alert(2);}test();var � test � = � function(){//预编译声明,运行时赋值 �  alert(3);}test();test � = � function(){//运行时,变量赋值 �  alert(4);}test();

11年9月13日星期二

Page 37: 高性能Javascript

JavaScript性能会影响到用户体验吗?

11年9月13日星期二

Page 38: 高性能Javascript

JavaScript � 性能已经直接影响到用户体验

11年9月13日星期二

Page 39: 高性能Javascript

JavaScript � is � Slow!

11年9月13日星期二

Page 40: 高性能Javascript

11年9月13日星期二

Page 41: 高性能Javascript

11年9月13日星期二

Page 42: 高性能Javascript

JavaScript � is � Fast!

11年9月13日星期二

Page 43: 高性能Javascript

JavaScript引擎

V8 � C++

JaegerMonkey � C++

JScript � JSctipt.Net

Nitro � C++

Karakan � C++

...

11年9月13日星期二

Page 44: 高性能Javascript

http://ie.microsoft.com/testdrive/benchmarks/sunspider/default.html

JavaScript运行越来越快

11年9月13日星期二

Page 45: 高性能Javascript

IE8 IE6 Sougou IE7 IE9Tt Chrome Maxyhon Firefox TheworldSe360 Other Opera Safari

http://www.1688.com/11年9月13日星期二

Page 46: 高性能Javascript

IE840.60%

IE639.81%

Sougou5.03%

3.74%3.09%

1.67%1.24%1.17%1.11%0.99%0.96%0.37%0.13%0.10%

IE8 IE6 Sougou IE7 IE9Tt Chrome Maxyhon Firefox TheworldSe360 Other Opera Safari

http://www.1688.com/11年9月13日星期二

Page 47: 高性能Javascript

但如果不了解,不注意,依然有可能写出非常低效(Inefficient)的JavaScript代码

11年9月13日星期二

Page 48: 高性能Javascript

Douglas � Crockford Steve � Sounders Nicholas.C.Zakes

大牛11年9月13日星期二

Page 49: 高性能Javascript

UI线程

11年9月13日星期二

Page 50: 高性能Javascript

Input output<!DOCTYPE � html>

<html><head>

<title>1688首页</title></head><body>

<div>hello</div><script>

doc.write(‘helloworld’);</script><div>world</div>

</body></html>

浏览器是如何渲染的?

?

11年9月13日星期二

Page 51: 高性能Javascript

Fetch Parse Flow Paint

URL Cache Tree DisplayList

Pixels

浏览器渲染过程

http://technotes-himanshu.blogspot.com/2010/05/html-dom.html11年9月13日星期二

Page 52: 高性能Javascript

Flow

Event

Paint

Script

执行脚本过程中的渲染

11年9月13日星期二

Page 53: 高性能Javascript

JS执行和浏览器渲染

11年9月13日星期二

Page 54: 高性能Javascript

<!DOCTYPE html><html>

<head><title>1688首页</title>

</head><body>

<div id=”a”>hello</div><script>

doc.write(‘helloworld’);</script><div id=”b”>world</div></body>

</html>

构建DOM 树

document

head

title

body

div

script

div

textNodeJS引擎创建了

textNode

11年9月13日星期二

Page 55: 高性能Javascript

阻塞:JS运行会中断HTML的渲染

11年9月13日星期二

Page 56: 高性能Javascript

浏览器是单线程作业同一时刻只能做一件事情,要么是用户界面更新,要么是JavaScript脚本执行

11年9月13日星期二

Page 57: 高性能Javascript

在UI线程忙碌的情况下,UI更新和JS执行都会被加入UI队列里,直到当前任务执行完毕,才会被激活

11年9月13日星期二

Page 58: 高性能Javascript

UI � Rendering � Threadtime

DOM

1.构建DOM

2.更新 � UI

11年9月13日星期二

Page 59: 高性能Javascript

UI � Rendering � Threadtime

DOM

渲染出此时的DOM

UI � Update

11年9月13日星期二

Page 60: 高性能Javascript

UI � Rendering � Threadtime

DOM

UI � Update Exec � JS

3.JS � 脚本新增DOM节点

11年9月13日星期二

Page 61: 高性能Javascript

UI � RenderingThreadtime

DOM

UI � Update Exec � JS UI � Update

4.更新UI

11年9月13日星期二

Page 62: 高性能Javascript

JavaScript执行时间 � = � UI不可响应时间

11年9月13日星期二

Page 63: 高性能Javascript

UI � Update Exec � JS UI � Update

time

UI可响应的

11年9月13日星期二

Page 64: 高性能Javascript

UI � Update Exec � JS UI � Update

time

UI不可响应的

假死

11年9月13日星期二

Page 65: 高性能Javascript

JavaScript执行过程耗时越久,浏览器等待响应用户输入的时间就越长,

就有多不好的用户体验

11年9月13日星期二

Page 66: 高性能Javascript

浏览器对于JavaScript运行的限制

1.调用栈大小限制

2.长时间运行限制

主要分为两类:

11年9月13日星期二

Page 67: 高性能Javascript

��� ���, ��� �

11年9月13日星期二

Page 68: 高性能Javascript

-� ���

11年9月13日星期二

Page 69: 高性能Javascript

浏览器限制

IE:500万条语句

Firefox:10秒

Safari:5秒

Chrome:没有单独的长运行脚本限制,替代做法是依赖于其崩溃检测系统来处理此类问题

Opera:没有长运行脚本限制

11年9月13日星期二

Page 70: 高性能Javascript

多久才算太久?

11年9月13日星期二

Page 71: 高性能Javascript

如果JavaScript运行了整整几秒钟,那么很可能你做错了什么....

--Brendan � Eich

11年9月13日星期二

Page 72: 高性能Javascript

在100毫秒以内响应用户输入,用户会认为自己在直接操作界面中的对象.超过100毫秒意味着用户会感到自己与界面失去联系.

-- � Jokob � Nielsen

11年9月13日星期二

Page 73: 高性能Javascript

佳实践:少于50毫秒

11年9月13日星期二

Page 74: 高性能Javascript

JavaScript Load最佳实践

11年9月13日星期二

Page 75: 高性能Javascript

浏览器在进行JavaScript下载,解析和运行都是会阻塞页面渲染的?

11年9月13日星期二

Page 76: 高性能Javascript

<!DOCTYPE html><html>

<head><title>1688首页</title>

</head><body>

<div>hello</div><script src=”jQuery.js”></script><div>world</div>

</body></html>

11年9月13日星期二

Page 77: 高性能Javascript

UI � Update JavaScript UI � Update

结果

11年9月13日星期二

Page 78: 高性能Javascript

UI � Update jQuery.js UI � Update

结果

11年9月13日星期二

Page 79: 高性能Javascript

UI � Update UI � Updatedownload parse run

结果

11年9月13日星期二

Page 80: 高性能Javascript

<!DOCTYPE html><html>

<head><title>1688首页</title>

</head><body>

<div>hello</div><script src=”jQuery.js”></script><div>world</div><script src=”yui2.js”></script><div>1688</div><script src=”yui3.js”></script>

</body></html>

11年9月13日星期二

Page 81: 高性能Javascript

UI � Update JavaScript UI � Update

结果

JavaScript UI � Update JavaScript

11年9月13日星期二

Page 82: 高性能Javascript

JavaScript Load最佳实践1:把JS放到页面底部

11年9月13日星期二

Page 83: 高性能Javascript

11年9月13日星期二

Page 84: 高性能Javascript

UI � Update JavaScriptUI � Update

结果

JavaScriptUI � Update JavaScript

11年9月13日星期二

Page 85: 高性能Javascript

<!DOCTYPE html><html>

<head><title>1688首页</title>

</head><body>

<div>hello</div><div>world</div><div>1688</div><script src=”jQuery.js”></script><script src=”yui2.js”></script><script src=”yui3.js”></script>

</body></html>

11年9月13日星期二

Page 86: 高性能Javascript

JavaScript Load最佳实践2:JS合并

11年9月13日星期二

Page 87: 高性能Javascript

<!DOCTYPE html><html>

<head><title>1688首页</title>

</head><body>

<div>hello</div><div>world</div><div>1688</div><script src=”jQuery-yui2-yui3.js”></script>

</body></html>

11年9月13日星期二

Page 88: 高性能Javascript

UI � Update UI � Update

结果

JavaScriptUI � Update

11年9月13日星期二

Page 89: 高性能Javascript

当然我们可以通过工具来完成自动合并

11年9月13日星期二

Page 90: 高性能Javascript

独角兽

Google � Page � Speed � Module

...

11年9月13日星期二

Page 91: 高性能Javascript

JavaScript Load最佳实践3:无阻塞异步加载JS

11年9月13日星期二

Page 92: 高性能Javascript

可选方案

Script DOM Element

Script Defer

Script Async

Iframed JS

XML HttpRequest Script Injection

11年9月13日星期二

Page 93: 高性能Javascript

Script DOM Element原理var script = document.createElement("script"),body = document.body; script.type = "text/javascript"; script.src = "foo.js"; body.insertBefore(script, body.firstChild);

11年9月13日星期二

Page 94: 高性能Javascript

UI � Update UI � Updaterun

结果

download parse

Time

11年9月13日星期二

Page 95: 高性能Javascript

类库选择YUI2(YAHOO.util.Get.script)

jQuery( jQuery.ajax)

LABjs

headjs

requirejs

SeaJs

...

11年9月13日星期二

Page 96: 高性能Javascript

Script � Defer

<script � defer � src="foo.js"></script>

11年9月13日星期二

Page 97: 高性能Javascript

浏览器支持情况

7.0 3.5 4.0 ? 5.0

11年9月13日星期二

Page 98: 高性能Javascript

Script � Async

<script � async � src="foo.js"></script>

11年9月13日星期二

Page 99: 高性能Javascript

浏览器支持情况

7.0 3.5 ? ? 5.0

11年9月13日星期二

Page 100: 高性能Javascript

Iframed � JSfunction � iframedJS(s){ � 

document.write("<iframe � id= � 'i'></iframe>"); � var � d � = � document.getElementById("i").contentWindow.document; � d.write('<!doctype � html><html><body><scr' � + � 'ipt � src="'+s

+'"></scr' � + � 'ipt></body></html>'); � window.setTimeout((function(){d.close();}),0);}

11年9月13日星期二

Page 101: 高性能Javascript

对同一个iframe多次进行doc.open+write+close,会增加浏览历史记录

Firefox � doc.write � iframe至页面,可能不能马上取到其引用

domain的潜在问题

缺点

11年9月13日星期二

Page 102: 高性能Javascript

XML � HttpRequest � Script � Injectionvar � xhr � = � new � XMLHttpRequest();xhr.open(‘get’,‘file.js’,true);xhr.onreadystatechange=function(){

if(xhr.staus==4){if(xhr.status>=200&& � xhr.status<300|| � xhr.status==304){

var � script � = � document.createElemet(‘script’);script.type= � ‘text/javascript’;script.text � = � xhr.responseText;document.body.appendChild(script);

}}

}

11年9月13日星期二

Page 103: 高性能Javascript

特点

可先下载,但不立即执行主流浏览器都支持有同域的要求

11年9月13日星期二

Page 104: 高性能Javascript

JavaScript � Compression �  佳实践

11年9月13日星期二

Page 105: 高性能Javascript

JavaScript � Compression �  佳实践1.上线前压缩

11年9月13日星期二

Page 106: 高性能Javascript

可选工具

YUI � Compressor

Google �  � Closure � Compiler

UglifyJS

Packer

...

11年9月13日星期二

Page 107: 高性能Javascript

JavaScript � Compression �  佳实践2.网络传输压缩

11年9月13日星期二

Page 108: 高性能Javascript

可选方案

gzip

compress

deflate

identity

11年9月13日星期二

Page 109: 高性能Javascript

JavaScript � Exec �  佳实践

11年9月13日星期二

Page 110: 高性能Javascript

JavaScript � Exec �  佳实践 � 1:使用定时器让出时间片

11年9月13日星期二

Page 111: 高性能Javascript

UI � Thread

UI � Update-Button JavaScript-click JavaScript-click

0 50

UI � Update-Button

JavaScript-click

JavaScript-clickTimer � coder

UI � Queue

setTimeout() called Timer code queued

11年9月13日星期二

Page 112: 高性能Javascript

使用定时器处理数组var � todo � = � items.concat();

setTime(function(){//取得数组的下个元素进行处理process(todo.shift());

if(todo.length � > � 0){setTimeout(arguments.callee,25);

} � else � {callback(items);

}},25);

11年9月13日星期二

Page 113: 高性能Javascript

分割任务function � multistep(steps,args,callback){

var � tasks � = � steps.concat();setTimeout(function(){

var � task � = � tasks.shitf();task.apply(null,args � || � []);

if(tasks.length � > � 0){setTimeout(arguments.callee,25);

}else{callback();

}},25);

}11年9月13日星期二

Page 114: 高性能Javascript

JavaScript � Exec �  佳实践 � 2:Web � Workers

11年9月13日星期二

Page 115: 高性能Javascript

11年9月13日星期二

Page 116: 高性能Javascript

Web � Workers � 没有绑定UI线程

11年9月13日星期二

Page 117: 高性能Javascript

//in � pagevar � worker � = � new � Worker("process.js"); � worker.onmessage � = � function(event){

useData(event.data);worker.postMessage(values);

};

//in � process.jsself.onmessage � = � function(event){ � 

var � items � = � event.data; � for � (var � i=0,len=items.length; � i � < � len; � i++){};process(items[i]); � self.postMessage(items);

}11年9月13日星期二

Page 118: 高性能Javascript

使用场景

编码/解码大字符串

复杂数学运算

大数组排序

11年9月13日星期二

Page 119: 高性能Javascript

浏览器支持情况

7.0 3.5 ? 10.6 4.0

11年9月13日星期二

Page 120: 高性能Javascript

DOM编程

11年9月13日星期二

Page 121: 高性能Javascript

天生就慢

ECAM � Land DOM � Land

ECMA每次访问DOM,都需要途经这座桥,并交纳”过桥费”.访问的次数越多,费用就越高

11年9月13日星期二

Page 122: 高性能Javascript

代价很昂贵

function � innerHTMLLoop(){for(var � count=0;count<1000;i++){

document.getElementById(‘i’).innerHTML+=”a”;

}}

11年9月13日星期二

Page 123: 高性能Javascript

优化后

function � innerHTMLLoop(){var � content=[];for(var � count=0;count<1000;i++){

content.push(‘a’);}document.getElementById(‘i’).innerHTML � = � content.join(‘’);

}

11年9月13日星期二

Page 124: 高性能Javascript

比较

innerHTML,createElement,cloneNode

案例:http://blog.stevenlevithan.com/archives/faster-than-innerhtml

http://stevenlevithan.com/demo/replaceHtml.html

11年9月13日星期二

Page 125: 高性能Javascript

重绘和重排

11年9月13日星期二

Page 126: 高性能Javascript

UI � Update时间 � = � UI不可用时间

11年9月13日星期二

Page 127: 高性能Javascript

<button � id="btn" � style="font-size: � 30px;">Click � Me</button><script � type="text/javascript"> � 

window.onload � = � function(){document.getElementById("btn").onclick � = � function(){ � 

var � div � = � document.createElement(“div”); � div.className � = � “tip”; � div.innerHTML � = � “You � clicked � me!”; � document.body.appendChild(div);

}; � }

</script>

11年9月13日星期二

Page 128: 高性能Javascript

JavaScript执行会触发重绘和重排会导致长时间UI � Update

11年9月13日星期二

Page 129: 高性能Javascript

浏览器渲染

11年9月13日星期二

Page 130: 高性能Javascript

重绘何时发生?

visibility

颜色

背景图片

不会触发layout改变

11年9月13日星期二

Page 131: 高性能Javascript

重排何时发生?

添加或删除可见的DOM节点

元素位置改变

元素尺寸改变(包括:外边框,内边距,边框厚度,宽度,高度等属性改变)

页面渲染器初始化

浏览器窗口尺寸改变

页面布局+几何属性改变都会触发重排

11年9月13日星期二

Page 132: 高性能Javascript

重绘<button � id="btn">Click � Me</button><script � type="text/javascript"> � 

window.onload � = � function(){document.getElementById("btn").onclick � = � function(){ � 

this.style.color � = � "#ff0";}

}; � </script>

重绘

11年9月13日星期二

Page 133: 高性能Javascript

重排

<button � id="btn" � style="font-size: � 30px;">Click � Me</button><script � type="text/javascript"> � window.onload � = � function(){

document.getElementById("btn").onclick � = � function(){ � var � div � = � document.createElement(“div”); � div.className � = � “tip”; � div.innerHTML � = � “You � clicked � me!”; � document.body.appendChild(div);

}; � }</script>

重排

11年9月13日星期二

Page 134: 高性能Javascript

小化重绘和重排

11年9月13日星期二

Page 135: 高性能Javascript

方法

批量修改样式,采用cssTest或者改变className的方式

批量修改DOM,使DOM脱离文档

缓存布局信息

让元素脱离动画流

事件委托

...

11年9月13日星期二

Page 136: 高性能Javascript

批量修改样式

var el = document.createElementById(‘mydiv’);el.style.borderLeft = ”1px”;el.style.borderRight = ‘2px’;el.style.padding = ‘5px’;

重绘

重绘

重绘

3次重绘

11年9月13日星期二

Page 137: 高性能Javascript

优化后

var el = document.createElementById(‘mydiv’);el.style.cssText = ‘border-left:1px;border-right:2px;padding:5px;’;

1次重绘

11年9月13日星期二

Page 138: 高性能Javascript

还可以这么做

var el = document.createElementById(‘mydiv’);el.className = ‘active’;

1次重绘

11年9月13日星期二

Page 139: 高性能Javascript

使DOM脱离文档

隐藏元素,应用修改,重新显示

使用文档片段(document � fragment)在当前DOM之外构造一个子树,在把它拷回文档

将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换原始元素

11年9月13日星期二

Page 140: 高性能Javascript

1.隐藏元素var � ul � = � document.getElementById(‘myList’);

ul.style.display � = � ‘none’;

appendDataToElement(ul,data);

ul.style.display � = � ‘block’;

11年9月13日星期二

Page 141: 高性能Javascript

文档片段

var � fragment � = � document.createDocmentFragment();

appendDataToElement(fragment,data);

document.getElementById(‘myList’).appendChild(‘f

ragment’)

11年9月13日星期二

Page 142: 高性能Javascript

缓存布局信息

myElement.style.left � = � 1+myElement.offsetLeft

+’px’;

if(myElement.offsetLeft>500){

stopAnimation();

}

非常的低效

11年9月13日星期二

Page 143: 高性能Javascript

可以这么优化

current++

myElement.style.left � = � current+’px’;

if(myElement.offsetLeft>500){

stopAnimation();

}

11年9月13日星期二

Page 144: 高性能Javascript

让元素脱离动画流

使用绝对位置定位页面上的元素,将其脱离文档流

让元素动起来.当它扩大时,会临时覆盖部分页面.这个时候只会小区域的重绘

当动画结束时恢复定位,从而知会下移一次文档的其他位置

11年9月13日星期二

Page 145: 高性能Javascript

事件委托

场景:当页面中存在大量元素,而且每⼀一个都要⼀一次或多次绑定事件处理器.

11年9月13日星期二

Page 146: 高性能Javascript

事件委托

结果是可能会影响性能.每绑定一个事件处理器都是有代价的,它要么加重了页面负担.,要么增加了运行期的执行时间.需要访问和修改的DOM元素越多, � 应用程序也就越慢.

11年9月13日星期二

Page 147: 高性能Javascript

解决方案

事件冒泡

例:YAHOO.util.Event.delegate

http://developer.yahoo.com/yui/event/

11年9月13日星期二

Page 148: 高性能Javascript

更多编程实践

更高效的代码(条件预加载,延迟加载,位操作等)

正则表达式优化(例:Detail详情延迟加载)

数据缓存(JS对象缓存,Ajax数据缓存等)

GC和避免内存泄漏(http://www.aliued.cn/2010/09/19/gc-and-js-memory-leak.html)

CSS3动画

其他见(Extreme � JavaScript � Performance.pdf)

11年9月13日星期二

Page 149: 高性能Javascript

工具

JS执行效率测试工具

内存泄漏检测工具

...

11年9月13日星期二

Page 150: 高性能Javascript

�����F

谢谢11年9月13日星期二