Contenu connexe Similaire à 高性能Javascript (7) 高性能Javascript2. About Me
谢传贵(阿贵)
前端开发部-前端架构组
新浪微薄@十月光风
11年9月13日星期二
19. 回顾
0.0 0.5 1.0 1.5
2.0 2.5 3.0 3.5
4.0 4.5 5.0 5.5
6.0 6.5
11年9月13日星期二
21. Topic
JavaScript运行过程
快速响应UI
更多编程实践
效率相关的工具
11年9月13日星期二
23. 从源码到可执行代码
解释 编译
(interpreted) (compiled)
11年9月13日星期二
24. (function(){
source.js(源码) alert(‘hello world’)
})
编译
helloworld.exe
0100100101010101
(二进制码)
执行
运行时环境 Runtime.exec(‘hello.exe’)
编译
11年9月13日星期二
25. (function(){
source.js(源码) alert(‘hello world’)
})
helloworld.exe 编译&运行
(二进制码)
运行时环境 Runtime.exec(‘hello.exe’)
解释
11年9月13日星期二
26. (function(){
alert(‘hello world’)
})
编译&运行
Runtime.exec(‘中间机器
解释器执行伪代码
运行时环境(浏览器)
解释
11年9月13日星期二
27. (function(){
alert(‘hello world’)
})
JavaScript Engine
编译&运行
Runtime.exec(‘中间机器
运行时环境(浏览器)
解释
11年9月13日星期二
30. JavaScript代码执行的过程
词法分析
语法检查
语法分析
将上下文中var申明 的变量放
入”栈”中 并赋值为undefined
预编译 读入”定义”的函数
运行时
运行
11年9月13日星期二
32. (function(){
alert(a); // 会报错么?
if(false){
var a=1;
}
})();
11年9月13日星期二
33. 函数执行前,函数内部变量均被声明
(function(){
alert(a); // 显示undefined,不报错
if(false){
var a=1; //不会执行到,亦被声明
}
})();
11年9月13日星期二
35. 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日星期二
36. 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日星期二
43. JavaScript引擎
V8 C++
JaegerMonkey C++
JScript JSctipt.Net
Nitro C++
Karakan C++
...
11年9月13日星期二
44. JavaScript运行越来越快
http://ie.microsoft.com/testdrive/benchmarks/sunspider/default.html
11年9月13日星期二
45. IE8 IE6 Sougou IE7 IE9
Tt Chrome Maxyhon Firefox Theworld
Se360 Other Opera Safari
http://www.1688.com/
11年9月13日星期二
46. IE8 IE6 Sougou IE7 IE9
Tt Chrome Maxyhon Firefox Theworld
Se360 Other Opera Safari
0.13%
0.10%
0.37%
0.96%
0.99%
1.11%
1.17%
1.24%
1.67%
3.09%
3.74%
Sougou IE8
5.03% 40.60%
IE6
39.81%
http://www.1688.com/
11年9月13日星期二
50. 浏览器是如何渲染的?
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日星期二
51. 浏览器渲染过程
Fetch Parse Flow Paint
Display
URL Cache Tree Pixels
List
http://technotes-himanshu.blogspot.com/2010/05/html-dom.html
11年9月13日星期二
52. 执行脚本过程中的渲染
Flow Paint
Script Event
11年9月13日星期二
54. 构建DOM 树
document
<!DOCTYPE html>
<html>
<head> head
<title>1688首页</title>
</head> title
<body>
<div id=”a”>hello</div> body
<script>
doc.write(‘helloworld’); div
</script>
<div id=”b”>world</div> script
</body> JS引擎创建了
</html> textNode textNode
div
11年9月13日星期二
55. 阻塞:
JS运行会中断HTML的渲染
11年9月13日星期二
56. 浏览器是单线程作业
同一时刻只能做一件事情,要么是用户界面更新,要么是JavaScript脚本执行
11年9月13日星期二
58. time
UI Rendering Thread
2.更新 UI
DOM
1.构建DOM
11年9月13日星期二
59. time
UI Rendering Thread
UI Update
渲染出此时的DOM
DOM
11年9月13日星期二
60. time
UI Rendering Thread
UI Update Exec JS
3.JS 脚本新增DOM节点
DOM
11年9月13日星期二
61. time
UI RenderingThread
UI Update Exec JS UI Update
4.更新UI
DOM
11年9月13日星期二
63. UI可响应的
UI Update Exec JS UI Update
time
11年9月13日星期二
64. UI不可响应的
UI Update Exec JS UI Update
time
假死
11年9月13日星期二
69. 浏览器限制
IE:500万条语句
Firefox:10秒
Safari:5秒
Chrome:没有单独的长运行脚本限制,替代做法是依赖
于其崩溃检测系统来处理此类问题
Opera:没有长运行脚本限制
11年9月13日星期二
72. 在100毫秒以内响应用户输
入,用户会认为自己在直接操
作界面中的对象.超过100毫
秒意味着用户会感到自己与
界面失去联系.
-- Jokob Nielsen
11年9月13日星期二
76. !DOCTYPE html
html
head
title1688首页/title
/head
body
divhello/div
script src=”jQuery.js”/script
divworld/div
/body
/html
11年9月13日星期二
77. 结果
UI Update JavaScript UI Update
11年9月13日星期二
78. 结果
UI Update jQuery.js UI Update
11年9月13日星期二
79. 结果
UI Update download parse run UI Update
11年9月13日星期二
80. !DOCTYPE html
html
head
title1688首页/title
/head
body
divhello/div
script src=”jQuery.js”/script
divworld/div
script src=”yui2.js”/script
div1688/div
script src=”yui3.js”/script
/body
/html
11年9月13日星期二
81. 结果
UI Update JavaScript UI Update JavaScript UI Update JavaScript
11年9月13日星期二
84. 结果
UI Update UI Update UI Update JavaScript JavaScript JavaScript
11年9月13日星期二
85. !DOCTYPE html
html
head
title1688首页/title
/head
body
divhello/div
divworld/div
div1688/div
script src=”jQuery.js”/script
script src=”yui2.js”/script
script src=”yui3.js”/script
/body
/html
11年9月13日星期二
87. !DOCTYPE html
html
head
title1688首页/title
/head
body
divhello/div
divworld/div
div1688/div
script src=”jQuery-yui2-yui3.js”/script
/body
/html
11年9月13日星期二
88. 结果
UI Update UI Update UI Update JavaScript
11年9月13日星期二
90. 独角兽
Google Page Speed Module
...
11年9月13日星期二
92. 可选方案
Script DOM Element
Script Defer
Script Async
Iframed JS
XML HttpRequest Script Injection
11年9月13日星期二
93. 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日星期二
94. 结果
UI Update run UI Update
Time
download parse
11年9月13日星期二
95. 类库选择
YUI2(YAHOO.util.Get.script)
jQuery( jQuery.ajax)
LABjs
headjs
requirejs
SeaJs
...
11年9月13日星期二
97. 浏览器支持情况
7.0 3.5 4.0 ? 5.0
11年9月13日星期二
99. 浏览器支持情况
7.0 3.5 ? ? 5.0
11年9月13日星期二
100. Iframed JS
function iframedJS(s){
document.write(iframe id= 'i'/iframe);
var d =
document.getElementById(i).contentWindow.docum
t;
d.write('!doctype htmlhtmlbodyscr' + 'ipt
src='+s
+'/scr' + 'ipt/body/html');
window.setTimeout((function(){d.close();}),0);
}
11年9月13日星期二
101. 缺点
对同一个iframe多次进行doc.open+write+close,会
增加浏览历史记录
Firefox doc.write iframe至页面,可能不能马上取到其
引用
domain的潜在问题
11年9月13日星期二
102. XML HttpRequest Script Injection
var xhr = new XMLHttpRequest();
xhr.open(‘get’,‘file.js’,true);
xhr.onreadystatechange=function(){
if(xhr.staus==4){
if(xhr.status=200 xhr.status300|| xhr.status==304){
var script = document.createElemet(‘script’);
script.type= ‘text/javascript’;
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
}
11年9月13日星期二
103. 特点
可先下载,但不立即执行
主流浏览器都支持
有同域的要求
11年9月13日星期二
106. 可选工具
YUI Compressor
Google Closure Compiler
UglifyJS
Packer
...
11年9月13日星期二
108. 可选方案
gzip
compress
deflate
identity
11年9月13日星期二
111. UI Thread
UI Update-Button JavaScript-click JavaScript-click
UI Queue
JavaScript-click
UI Update-Button
Timer coder
JavaScript-click
0 50 setTimeout() called Timer code queued
11年9月13日星期二
112. 使用定时器处理数组
var todo = items.concat();
setTime(function(){
//取得数组的下个元素进行处理
process(todo.shift());
if(todo.length 0){
setTimeout(arguments.callee,25);
} else {
callback(items);
}
},25);
11年9月13日星期二
113. 分割任务
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();
}
11年9月13日星期二
},25);
117. //in page
var worker = new Worker(process.js);
worker.onmessage = function(event){
useData(event.data);
worker.postMessage(values);
};
//in process.js
self.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日星期二
118. 使用场景
编码/解码大字符串
复杂数学运算
大数组排序
11年9月13日星期二
119. 浏览器支持情况
7.0 3.5 ? 10.6 4.0
11年9月13日星期二
121. 天生就慢
ECAM Land DOM Land
ECMA每次访问DOM,都需要途经这座桥,并交纳”过桥费”.访问的次数越多,费用就越高
11年9月13日星期二
122. 代价很昂贵
function innerHTMLLoop(){
for(var count=0;count1000;i++){
document.getElementById(‘i’).innerHTML
+=”a”;
}
}
11年9月13日星期二
123. 优化后
function innerHTMLLoop(){
var content=[];
for(var count=0;count1000;i++){
content.push(‘a’);
}
document.getElementById(‘i’).innerHTML =
content.join(‘’);
}
11年9月13日星期二
124. 比较
innerHTML,createElement,cloneNode
案例:http://blog.stevenlevithan.com/archives/faster-than-innerhtml
http://stevenlevithan.com/demo/replaceHtml.html
11年9月13日星期二
127. 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日星期二
130. 重绘何时发生?
visibility
颜色
背景图片
不会触发layout改变
11年9月13日星期二
131. 重排何时发生?
添加或删除可见的DOM节点
元素位置改变
元素尺寸改变(包括:外边框,内边距,边框厚度,宽度,高度
等属性改变)
页面渲染器初始化
浏览器窗口尺寸改变
页面布局+几何属性改变都会触发重排
11年9月13日星期二
132. 重绘
button id=btnClick Me/button
script type=text/javascript
window.onload = function(){
document.getElementById(btn).onclick = function(){
this.style.color = #ff0;
} 重绘
};
/script
11年9月13日星期二
133. 重排
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日星期二
135. 方法
批量修改样式,采用cssTest或者改变className的方式
批量修改DOM,使DOM脱离文档
缓存布局信息
让元素脱离动画流
事件委托
...
11年9月13日星期二
136. 批量修改样式
var el = document.createElementById(‘mydiv’);
el.style.borderLeft = ”1px”;
重绘
el.style.borderRight = ‘2px’;
el.style.padding = ‘5px’; 重绘
重绘
3次重绘
11年9月13日星期二
137. 优化后
var el = document.createElementById(‘mydiv’);
el.style.cssText = ‘border-left:1px;border-right:2px;
padding:5px;’;
1次重绘
11年9月13日星期二
138. 还可以这么做
var el = document.createElementById(‘mydiv’);
el.className = ‘active’;
1次重绘
11年9月13日星期二
139. 使DOM脱离文档
隐藏元素,应用修改,重新显示
使用文档片段(document fragment)在当前DOM之外
构造一个子树,在把它拷回文档
将原始元素拷贝到一个脱离文档的节点中,修改副本,完
成后再替换原始元素
11年9月13日星期二
140. 1.隐藏元素
var ul = document.getElementById(‘myList’);
ul.style.display = ‘none’;
appendDataToElement(ul,data);
ul.style.display = ‘block’;
11年9月13日星期二
141. 文档片段
var fragment = document.createDocmentFragment();
appendDataToElement(fragment,data);
document.getElementById(‘myList’).appendChild(‘f
ragment’)
11年9月13日星期二
142. 缓存布局信息
myElement.style.left = 1+myElement.offsetLeft
+’px’;
if(myElement.offsetLeft500){
stopAnimation();
}
非常的低效
11年9月13日星期二
143. 可以这么优化
current++
myElement.style.left = current+’px’;
if(myElement.offsetLeft500){
stopAnimation();
}
11年9月13日星期二
144. 让元素脱离动画流
使用绝对位置定位页面上的元素,将其脱离文档流
让元素动起来.当它扩大时,会临时覆盖部分页面.这个时
候只会小区域的重绘
当动画结束时恢复定位,从而知会下移一次文档的其他
位置
11年9月13日星期二
145. 事件委托
场景:当页面中存在大量元素,而且每⼀一个都要⼀一次
或多次绑定事件处理器.
11年9月13日星期二
146. 事件委托
结果是可能会影响性能.每绑定一个事件处理器
都是有代价的,它要么加重了页面负担.,要么增加
了运行期的执行时间.需要访问和修改的DOM元
素越多, 应用程序也就越慢.
11年9月13日星期二
147. 解决方案
事件冒泡
例:YAHOO.util.Event.delegate
http://developer.yahoo.com/yui/event/
11年9月13日星期二
148. 更多编程实践
更高效的代码(条件预加载,延迟加载,位操作等)
正则表达式优化(例: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日星期二
149. 工具
JS执行效率测试工具
内存泄漏检测工具
...
11年9月13日星期二