SlideShare a Scribd company logo
1 of 9
 Javascript 性能优化总结<br />Out-of-the-flow DOM Manipulation(在页面外进行DOM操作)<br />This pattern lets us create multiple elements and insert them into the DOM triggering a single reflow。<br />如果有多个对DOM的操作,我们最好先将元素从DOM树中剥离开来,再对这个元素进行一系列的操作之后,最后再通过appendChild或者insertBefore插入原来位置的DOM树中。这样就使得页面的reflow的次数最小化。<br />问题: <br />The problems is, this can cause a reflow for each anchor。每设置个className都导致一次Reflow.<br />function updateAllAnchors(element, anchorClass) {<br />  var anchors = element.getElementsByTagName('a');<br />  for (var i = 0, length = anchors.length; i < length; i ++) {<br />    anchors[i].className = anchorClass;<br />  }<br />}<br />解决方案:<br />为了解决这个问题,我们可以先remove这些元素,然后更新这些元素,最后再<br />把元素插入到元素原来的位置。<br />* Remove an element and provide a function that inserts it into its original position<br /> * @param element {Element} The element to be temporarily removed<br /> * @return {Function} A function that inserts the element into its original position<br /> **/<br />function removeToInsertLater(element) {<br />  var parentNode = element.parentNode;<br />  var nextSibling = element.nextSibling;<br />  parentNode.removeChild(element);<br />  return function() {<br />    if (nextSibling) {<br />      parentNode.insertBefore(element, nextSibling);<br />    } else {<br />      parentNode.appendChild(element);<br />    }<br />  };<br />function updateAllAnchors(element, anchorClass) {<br />  var insertFunction = removeToInsertLater(element);<br />  var anchors = element.getElementsByTagName('a');<br />  for (var i = 0, length = anchors.length; i < length; i ++) {<br />    anchors[i].className = anchorClass;<br />  }<br />  insertFunction();}<br /> DocumentFragment DOM Generation (利用DocumentFragment产生DOM)<br />We create a DocumentFragment outside of the DOM (so it is out-of-the-flow),这样可以页面一次Reflow.<br />例如,我们需要一次插入多个html标签,<br />function addAnchors(element) {<br />  var anchor;<br />  for (var i = 0; i < 10; i ++) {<br />    anchor = document.createElement('a');<br />    anchor.innerHTML = 'test';<br />    element.appendChild(anchor);<br />  }<br />}<br />我们应该如下写:<br />function addAnchors(element) {<br />  var anchor, fragment = document.createDocumentFragment();<br />  for (var i = 0; i < 10; i ++) {<br />    anchor = document.createElement('a');<br />    anchor.innerHTML = 'test';<br />    fragment.appendChild(anchor);<br />  }<br />  element.appendChild(fragment);<br />}<br />CSS class switching DOM manipulation(DOM 操作css 样式)<br />对DOM的css操作,每操作一次,都会导致一次页面的reflow.<br />例如: function selectAnchor(element) {<br />  element.style.fontWeight = 'bold';<br />  element.style.textDecoration = 'none';<br />  element.style.color = '#000';<br />}<br />应该如下写:<br />.selectedAnchor {<br />  font-weight: bold;<br />  text-decoration: none;<br />  color: #000;<br />}<br />function selectAnchor(element) {<br />  element.className = 'selectedAnchor';<br />}<br />4.Single Element DOM Generation<br />This pattern lets us create and add a single element to the DOM triggering a single reflow. After creating the element, make all changes to the new element before adding it to the DOM.<br />在创建一个元素之后,先对元素设置属性之后在增加dom节点中。<br />例如: function addAnchor(parentElement, anchorText, anchorClass) {<br />  var element = document.createElement('a');<br />  parentElement.appendChild(element);<br />  element.innerHTML = anchorText;<br />  element.className = anchorClass;<br />}<br />应该写成: <br />function addAnchor(parentElement, anchorText, anchorClass) {<br />  var element = document.createElement('a');<br />  element.innerHTML = anchorText;<br />  element.className = anchorClass;<br />  parentElement.appendChild(element);<br />}<br />5.循环的使用技巧<br />onload = function(){  Watch.start(quot;
Store lengthquot;
);  var p2 = document.getElementsByTagName(quot;
pquot;
);  //第一次循環使用  for (var i = 0, l = p2.length; i < l; i++) {    p2[i].innerHTML = quot;
Change againquot;
;  }  //第二次循環使用  for (var i = 0, l = p2.length; i < l; i++) {    p2[i].innerHTML = quot;
Change againquot;
;  }  Watch.stop();  ///////////////////////////////////////////////////////////////////////  Watch.start(quot;
Store to arrayquot;
);  var p = document.getElementsByTagName(quot;
pquot;
);  var arr = [];  var c = null;  //儲存進數組  //注意這種循環的使用方式,下同  for (var i = 0; c = p[i++];) {    arr.push(c);  }  //第一次循環使用  for (var i = 0; c = arr[i++];) {    c.innerHTML = quot;
Change backup.quot;
  }  //第二次循環使用  for (var i = 0; c = arr[i++];) {    c.innerHTML = quot;
Change backup.quot;
  }  Watch.stop();  //打印结果  Watch.report();}<br />第二种方法的效率大约是第一种方法的两倍。<br />而对于将,比如改变结束条件判断的方式,不根据长度(length)递增的形式,而是使用递减的方式,这个经过测试,在一定程度上能提高循环的性能,比如(for(var i=length-1;i>=0;i–),但实际上却差不多。<br />6.缩短作用域链(减少闭包)<br />缩短作用域链,说简单点就是尽量使用局部变量来储存外部的对象。对于在循环中重复出现的对象,这个尤其具有优化效果;对于在闭包函数外的对象,当需要在闭包内使用的时候,可以在闭包内声明一个局部变量来储存该对象;还有对DOM元素的length属性、或者在DOM操作的循环中单个DOM元素使用局部变量来储存,也十分具有优化效果。目的就是使得在数据存取的过程中从作用域链中能最快的取出来,而最快的取出来的前提就是需要对象或者变量在作用域链的顶部。经过测试表明:局部变量的存取速度是最快的。所以将作用域外的对象局部引用化,也是不错的优化方式。<br />例子一:将NodeList的length属性缓存起来,这样就可以避免每次重新计算length属性,重新查询一遍DOM树。var d = document.getElementsByTagName(quot;
divquot;
);for(var i=0, l = d.length; i<l; i++){  //code here...}<br />//例子二:将每一个DOM元素局部化,因为对每一个DOM元素的操作,都需要在NodeList中去查询这个DOM元素。var d = document.getElementsByTagName(quot;
divquot;
);for(var i=0, l = d.length; i<l; i++){  var item = d[i];  item.className=quot;
activequot;
;  item.title = quot;
active itemquot;
;  //......}<br />//例子三:储存重复出现的对象或者方法,特别是在循环中。将document.body缓存起来,这样在循环里读取的速度就非常快了。var b = document.body;for(var i=0;i<10;i++){  b.appendChild(document.createTextNode(quot;
some textquot;
));}<br />//=====================================//例子四:对闭包外的对象或者变量在闭包内局部化。//msg在setTimeout闭包参数的作用域外function setupAlertTimeout() {  var msg = 'Message to alert';window.setTimeout(function() { alert(msg); }, 100);}//下面这个更快,将变量声明放到闭包内,使得读取速度更快。function setupAlertTimeout() {  window.setTimeout(function() {    var msg = 'Message to alert';    alert(msg);  }, 100);}//再来个更快的,这下避免使用闭包来作为setTimeout的参数,使得程序运行更快。function alertMsg() {  var msg = 'Message to alert';  alert(msg);}function setupAlertTimeout() {  window.setTimeout(alertMsg, 100);} <br />对于上面例子四中关于闭包的使用,在这里解释一下:闭包非常强大而且使用,但是它也有很多缺陷,比如:是造成很多内存泄漏的罪魁祸首;声明一个闭包比声明一个不是闭包的内部函数更慢,比声明一个静态函数就更慢了。因此得出了上面的结论。<br />还有,对于缩短作用域链的一个更直白的解释例子如下:<br />var a = 'a';function createFunctionWithClosure() {  var b = 'b';  return function () {    var c = 'c';    a;    b;    c;  };}var f = createFunctionWithClosure();f();<br />如上所示:当函数f调用的时候,读取a比读取b慢,比读取c又更慢。这就是作用域链的存取速度导致的性能问题,在HTMLCollection、NodeList中更甚。<br />
Javascript 性能优化总结.docx
Javascript 性能优化总结.docx
Javascript 性能优化总结.docx
Javascript 性能优化总结.docx
Javascript 性能优化总结.docx
Javascript 性能优化总结.docx
Javascript 性能优化总结.docx
Javascript 性能优化总结.docx

More Related Content

What's hot

Java script closures
Java script closuresJava script closures
Java script closures
skywalker1114
 
Node.js從無到有 基本課程
Node.js從無到有 基本課程Node.js從無到有 基本課程
Node.js從無到有 基本課程
Simon Su
 
浮云脱水小说站的搭建
浮云脱水小说站的搭建浮云脱水小说站的搭建
浮云脱水小说站的搭建
jondynet
 
香港六合彩
香港六合彩香港六合彩
Node.js 入門 - 前端工程開發實務訓練
Node.js 入門 - 前端工程開發實務訓練Node.js 入門 - 前端工程開發實務訓練
Node.js 入門 - 前端工程開發實務訓練
Joseph Chiang
 
Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methods
yiditushe
 

What's hot (19)

Java script closures
Java script closuresJava script closures
Java script closures
 
Node.js從無到有 基本課程
Node.js從無到有 基本課程Node.js從無到有 基本課程
Node.js從無到有 基本課程
 
J Query Learn
J Query LearnJ Query Learn
J Query Learn
 
Osgi Intro
Osgi IntroOsgi Intro
Osgi Intro
 
浮云脱水小说站的搭建
浮云脱水小说站的搭建浮云脱水小说站的搭建
浮云脱水小说站的搭建
 
香港六合彩
香港六合彩香港六合彩
香港六合彩
 
ev2oik
ev2oikev2oik
ev2oik
 
Node.js 淺談socket.io
Node.js   淺談socket.ioNode.js   淺談socket.io
Node.js 淺談socket.io
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐
 
程式人雜誌 2015年三月
程式人雜誌 2015年三月程式人雜誌 2015年三月
程式人雜誌 2015年三月
 
JCConf2015: groovy to gradle
 JCConf2015: groovy to gradle JCConf2015: groovy to gradle
JCConf2015: groovy to gradle
 
Drag & drop
Drag & dropDrag & drop
Drag & drop
 
Node.js 入門 - 前端工程開發實務訓練
Node.js 入門 - 前端工程開發實務訓練Node.js 入門 - 前端工程開發實務訓練
Node.js 入門 - 前端工程開發實務訓練
 
Http Headers 與 Cache 機制(2016)
Http Headers 與 Cache 機制(2016)Http Headers 與 Cache 機制(2016)
Http Headers 與 Cache 機制(2016)
 
Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methods
 
程式人雜誌 2015年五月
程式人雜誌 2015年五月程式人雜誌 2015年五月
程式人雜誌 2015年五月
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计
 
Npm 套件管理 & 常用開發工具介紹
Npm 套件管理 & 常用開發工具介紹Npm 套件管理 & 常用開發工具介紹
Npm 套件管理 & 常用開發工具介紹
 
用最潮的 Java script 盡情開發 kde qt 程式
用最潮的 Java script 盡情開發 kde qt 程式用最潮的 Java script 盡情開發 kde qt 程式
用最潮的 Java script 盡情開發 kde qt 程式
 

Viewers also liked (8)

The woman is on the hippopotamus jeferson & eduarda
The woman is on the hippopotamus jeferson &  eduardaThe woman is on the hippopotamus jeferson &  eduarda
The woman is on the hippopotamus jeferson & eduarda
 
Parachute procudure
Parachute procudureParachute procudure
Parachute procudure
 
Sunu4
Sunu4Sunu4
Sunu4
 
Cp Overview Bs
Cp Overview BsCp Overview Bs
Cp Overview Bs
 
Smart – way to success
Smart – way to successSmart – way to success
Smart – way to success
 
Pemrograman berorientasi objek lanjutan
Pemrograman berorientasi objek lanjutanPemrograman berorientasi objek lanjutan
Pemrograman berorientasi objek lanjutan
 
Modul Praktek Java OOP
Modul Praktek Java OOP Modul Praktek Java OOP
Modul Praktek Java OOP
 
modul Java dasar fundamental (OOP)
modul Java dasar fundamental (OOP)modul Java dasar fundamental (OOP)
modul Java dasar fundamental (OOP)
 

Similar to Javascript 性能优化总结.docx

Similar to Javascript 性能优化总结.docx (20)

JavaScript Advanced Skill
JavaScript Advanced SkillJavaScript Advanced Skill
JavaScript Advanced Skill
 
让我们的页面跑得更快
让我们的页面跑得更快让我们的页面跑得更快
让我们的页面跑得更快
 
【第一季第四期】JavaScript Optimization
【第一季第四期】JavaScript Optimization【第一季第四期】JavaScript Optimization
【第一季第四期】JavaScript Optimization
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践
 
Web base 吴志华
Web base 吴志华Web base 吴志华
Web base 吴志华
 
javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当
 
jQuery介绍@disandu.com
jQuery介绍@disandu.comjQuery介绍@disandu.com
jQuery介绍@disandu.com
 
Introduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDKIntroduction to Parse JavaScript SDK
Introduction to Parse JavaScript SDK
 
Script with engine
Script with engineScript with engine
Script with engine
 
钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非
 
HTML5概览
HTML5概览HTML5概览
HTML5概览
 
Java script closures
Java script closuresJava script closures
Java script closures
 
旺铺前端设计和实现
旺铺前端设计和实现旺铺前端设计和实现
旺铺前端设计和实现
 
Vue.js
Vue.jsVue.js
Vue.js
 
前端MVC之backbone
前端MVC之backbone前端MVC之backbone
前端MVC之backbone
 
YUI ─ 阿大
YUI ─ 阿大YUI ─ 阿大
YUI ─ 阿大
 
Js dom
Js domJs dom
Js dom
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践
 

Javascript 性能优化总结.docx

  • 1. Javascript 性能优化总结<br />Out-of-the-flow DOM Manipulation(在页面外进行DOM操作)<br />This pattern lets us create multiple elements and insert them into the DOM triggering a single reflow。<br />如果有多个对DOM的操作,我们最好先将元素从DOM树中剥离开来,再对这个元素进行一系列的操作之后,最后再通过appendChild或者insertBefore插入原来位置的DOM树中。这样就使得页面的reflow的次数最小化。<br />问题: <br />The problems is, this can cause a reflow for each anchor。每设置个className都导致一次Reflow.<br />function updateAllAnchors(element, anchorClass) {<br /> var anchors = element.getElementsByTagName('a');<br /> for (var i = 0, length = anchors.length; i < length; i ++) {<br /> anchors[i].className = anchorClass;<br /> }<br />}<br />解决方案:<br />为了解决这个问题,我们可以先remove这些元素,然后更新这些元素,最后再<br />把元素插入到元素原来的位置。<br />* Remove an element and provide a function that inserts it into its original position<br /> * @param element {Element} The element to be temporarily removed<br /> * @return {Function} A function that inserts the element into its original position<br /> **/<br />function removeToInsertLater(element) {<br /> var parentNode = element.parentNode;<br /> var nextSibling = element.nextSibling;<br /> parentNode.removeChild(element);<br /> return function() {<br /> if (nextSibling) {<br /> parentNode.insertBefore(element, nextSibling);<br /> } else {<br /> parentNode.appendChild(element);<br /> }<br /> };<br />function updateAllAnchors(element, anchorClass) {<br /> var insertFunction = removeToInsertLater(element);<br /> var anchors = element.getElementsByTagName('a');<br /> for (var i = 0, length = anchors.length; i < length; i ++) {<br /> anchors[i].className = anchorClass;<br /> }<br /> insertFunction();}<br /> DocumentFragment DOM Generation (利用DocumentFragment产生DOM)<br />We create a DocumentFragment outside of the DOM (so it is out-of-the-flow),这样可以页面一次Reflow.<br />例如,我们需要一次插入多个html标签,<br />function addAnchors(element) {<br /> var anchor;<br /> for (var i = 0; i < 10; i ++) {<br /> anchor = document.createElement('a');<br /> anchor.innerHTML = 'test';<br /> element.appendChild(anchor);<br /> }<br />}<br />我们应该如下写:<br />function addAnchors(element) {<br /> var anchor, fragment = document.createDocumentFragment();<br /> for (var i = 0; i < 10; i ++) {<br /> anchor = document.createElement('a');<br /> anchor.innerHTML = 'test';<br /> fragment.appendChild(anchor);<br /> }<br /> element.appendChild(fragment);<br />}<br />CSS class switching DOM manipulation(DOM 操作css 样式)<br />对DOM的css操作,每操作一次,都会导致一次页面的reflow.<br />例如: function selectAnchor(element) {<br /> element.style.fontWeight = 'bold';<br /> element.style.textDecoration = 'none';<br /> element.style.color = '#000';<br />}<br />应该如下写:<br />.selectedAnchor {<br /> font-weight: bold;<br /> text-decoration: none;<br /> color: #000;<br />}<br />function selectAnchor(element) {<br /> element.className = 'selectedAnchor';<br />}<br />4.Single Element DOM Generation<br />This pattern lets us create and add a single element to the DOM triggering a single reflow. After creating the element, make all changes to the new element before adding it to the DOM.<br />在创建一个元素之后,先对元素设置属性之后在增加dom节点中。<br />例如: function addAnchor(parentElement, anchorText, anchorClass) {<br /> var element = document.createElement('a');<br /> parentElement.appendChild(element);<br /> element.innerHTML = anchorText;<br /> element.className = anchorClass;<br />}<br />应该写成: <br />function addAnchor(parentElement, anchorText, anchorClass) {<br /> var element = document.createElement('a');<br /> element.innerHTML = anchorText;<br /> element.className = anchorClass;<br /> parentElement.appendChild(element);<br />}<br />5.循环的使用技巧<br />onload = function(){  Watch.start(quot; Store lengthquot; );  var p2 = document.getElementsByTagName(quot; pquot; );  //第一次循環使用  for (var i = 0, l = p2.length; i < l; i++) {    p2[i].innerHTML = quot; Change againquot; ;  }  //第二次循環使用  for (var i = 0, l = p2.length; i < l; i++) {    p2[i].innerHTML = quot; Change againquot; ;  }  Watch.stop();  ///////////////////////////////////////////////////////////////////////  Watch.start(quot; Store to arrayquot; );  var p = document.getElementsByTagName(quot; pquot; );  var arr = [];  var c = null;  //儲存進數組  //注意這種循環的使用方式,下同  for (var i = 0; c = p[i++];) {    arr.push(c);  }  //第一次循環使用  for (var i = 0; c = arr[i++];) {    c.innerHTML = quot; Change backup.quot;   }  //第二次循環使用  for (var i = 0; c = arr[i++];) {    c.innerHTML = quot; Change backup.quot;   }  Watch.stop();  //打印结果  Watch.report();}<br />第二种方法的效率大约是第一种方法的两倍。<br />而对于将,比如改变结束条件判断的方式,不根据长度(length)递增的形式,而是使用递减的方式,这个经过测试,在一定程度上能提高循环的性能,比如(for(var i=length-1;i>=0;i–),但实际上却差不多。<br />6.缩短作用域链(减少闭包)<br />缩短作用域链,说简单点就是尽量使用局部变量来储存外部的对象。对于在循环中重复出现的对象,这个尤其具有优化效果;对于在闭包函数外的对象,当需要在闭包内使用的时候,可以在闭包内声明一个局部变量来储存该对象;还有对DOM元素的length属性、或者在DOM操作的循环中单个DOM元素使用局部变量来储存,也十分具有优化效果。目的就是使得在数据存取的过程中从作用域链中能最快的取出来,而最快的取出来的前提就是需要对象或者变量在作用域链的顶部。经过测试表明:局部变量的存取速度是最快的。所以将作用域外的对象局部引用化,也是不错的优化方式。<br />例子一:将NodeList的length属性缓存起来,这样就可以避免每次重新计算length属性,重新查询一遍DOM树。var d = document.getElementsByTagName(quot; divquot; );for(var i=0, l = d.length; i<l; i++){  //code here...}<br />//例子二:将每一个DOM元素局部化,因为对每一个DOM元素的操作,都需要在NodeList中去查询这个DOM元素。var d = document.getElementsByTagName(quot; divquot; );for(var i=0, l = d.length; i<l; i++){  var item = d[i];  item.className=quot; activequot; ;  item.title = quot; active itemquot; ;  //......}<br />//例子三:储存重复出现的对象或者方法,特别是在循环中。将document.body缓存起来,这样在循环里读取的速度就非常快了。var b = document.body;for(var i=0;i<10;i++){  b.appendChild(document.createTextNode(quot; some textquot; ));}<br />//=====================================//例子四:对闭包外的对象或者变量在闭包内局部化。//msg在setTimeout闭包参数的作用域外function setupAlertTimeout() {  var msg = 'Message to alert';window.setTimeout(function() { alert(msg); }, 100);}//下面这个更快,将变量声明放到闭包内,使得读取速度更快。function setupAlertTimeout() {  window.setTimeout(function() {    var msg = 'Message to alert';    alert(msg);  }, 100);}//再来个更快的,这下避免使用闭包来作为setTimeout的参数,使得程序运行更快。function alertMsg() {  var msg = 'Message to alert';  alert(msg);}function setupAlertTimeout() {  window.setTimeout(alertMsg, 100);} <br />对于上面例子四中关于闭包的使用,在这里解释一下:闭包非常强大而且使用,但是它也有很多缺陷,比如:是造成很多内存泄漏的罪魁祸首;声明一个闭包比声明一个不是闭包的内部函数更慢,比声明一个静态函数就更慢了。因此得出了上面的结论。<br />还有,对于缩短作用域链的一个更直白的解释例子如下:<br />var a = 'a';function createFunctionWithClosure() {  var b = 'b';  return function () {    var c = 'c';    a;    b;    c;  };}var f = createFunctionWithClosure();f();<br />如上所示:当函数f调用的时候,读取a比读取b慢,比读取c又更慢。这就是作用域链的存取速度导致的性能问题,在HTMLCollection、NodeList中更甚。<br />