十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
循环循环是很常用的一个控制结构,大部分东西要依靠它来完成,在JavaScript中,我们可以使用for(;;),while(),for(in)三种循环,事实上,这三种循环中for(in)的效率极差,因为他需要查询散列键,只要可以就应该尽量少用。for(;;)和while循环的性能应该说基本(平时使用时)等价。而事实上,如何使用这两个循环,则有很大讲究。我在测试中有些很有意思的情况,见附录。最后得出的结论是:如果是循环变量递增或递减,不要单独对循环变量赋值,应该在它最后一次读取的时候使用嵌套的++或--操作符。如果要与数组的长度作比较,应该事先把数组的length属性放入一个局部变量中,减少查询次数。举例,假设arr是一个数组,最佳的遍历元素方式为:for(var i=0, len = arr.length;i或者,如果无所谓顺序的话:for(var i=arr.length;i0;i--){...}局部变量和全局变量局部变量的速度要比全局变量的访问速度更快,因为全局变量其实是全局对象的成员,而局部变量是放在函数的栈当中的。不使用Eval使用eval相当于在运行时再次调用解释引擎对内容进行运行,需要消耗大量时间。这时候使用JavaScript所支持的闭包可以实现函数模版(关于闭包的内容请参考函数式编程的有关内容)减少对象查找因为JavaScript的解释性,所以a.b.c.d.e,需要进行至少4次查询操作,先检查a再检查a中的b,再检查b中的c,如此往下。所以如果这样的表达式重复出现,只要可能,应该尽量少出现这样的表达式,可以利用局部变量,把它放入一个临时的地方进行查询。这一点可以和循环结合起来,因为我们常常要根据字符串、数组的长度进行循环,而通常这个长度是不变的,比如每次查询a.length,就要额外进行一个操作,而预先把varlen=a.length,则就少了一次查询。字符串连接如果是追加字符串,最好使用s+=anotherStr操作,而不是要使用s=s+anotherStr。如果要连接多个字符串,应该少使用+=,如s+=a;s+=b;s+=c;应该写成s+=a + b + c;而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存。怎么用呢?使用JavaScript数组来收集,最后使用join方法连接起来,如下var buf = new Array();for(var i = 0; i 100; i++){ buf.push(i.toString());}var all = buf.join("");类型转换类型转换是大家常犯的错误,因为JavaScript是动态类型语言,你不能指定变量的类型。1.把数字转换成字符串,应用"" + 1,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说:("" + ) String() .toString() new String() 这条其实和下面的“直接量”有点类似,尽量使用编译时就能使用的内部操作要比运行时使用的用户操作要快。String()属于内部函数,所以速度很快,而.toString()要查询原型中的函数,所以速度逊色一些,new String()用于返回一个精确的副本。2.浮点数转换成整型,这个更容易出错,很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,我们应该使用Math.floor()或者Math.round()。另外,和第二节的对象查找中的问题不一样,Math是内部对象,所以Math.floor()其实并没有多少查询方法和调用的时间,速度是最快的。3.对于自定义的对象,如果定义了toString()方法来进行类型转换的话,推荐显式调用toString(),因为内部的操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String,所以直接调用这个方法效率会更高使用直接量其实这个影响倒比较小,可以忽略。什么叫使用直接量,比如,JavaScript支持使用 [param,param,param,...]来直接表达一个数组,以往我们都使用new Array(param,param,...),使用前者是引擎直接解释的,后者要调用一个Array内部构造器,所以要略微快一点点。同样,var foo = {}的方式也比var foo = new Object();快,var reg = /../;要比var reg=new RegExp()快。字符串遍历操作对字符串进行循环操作,譬如替换、查找,应使用正则表达式,因为本身JavaScript的循环速度就比较慢,而正则表达式的操作是用C写成的语言的API,性能很好。高级对象自定义高级对象和Date、RegExp对象在构造时都会消耗大量时间。如果可以复用,应采用缓存的方式。DOM相关插入HTML很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以找一个容器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。对象查询使用[""]查询要比.items()更快,这和前面的减少对象查找的思路是一样的,调用.items()增加了一次查询和函数的调用。创建DOM节点通常我们可能会使用字符串直接写HTML来创建节点,其实这样做无法保证代码的有效性字符串操作效率低所以应该是用document.createElement()方法,而如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,你需要设置多次元素的属性,使用 cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元素,应该先准备一个样板节点。定时器如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval。setTimeout每次要重新设置一个定时器。其他脚本引擎据我测试Microsoft的JScript的效率较Mozilla的Spidermonkey要差很多,无论是执行速度还是内存管理上,因为JScript现在基本也不更新了。但SpiderMonkey不能使用ActiveXObject文件优化文件优化也是一个很有效的手段,删除所有的空格和注释,把代码放入一行内,可以加快下载的速度,注意,是下载的速度而不是解析的速度,如果是本地,注释和空格并不会影响解释和执行速度。总结本文总结了我在JavaScript编程中所找到的提高JavaScript运行性能的一些方法,其实这些经验都基于几条原则:直接拿手头现成的东西比较快,如局部变量比全局变量快,直接量比运行时构造对象快等等。尽可能少地减少执行次数,比如先缓存需要多次查询的。尽可能使用语言内置的功能,比如串链接。尽可能使用系统提供的API,因为这些API是编译好的二进制代码,执行效率很高同时,一些基本的算法上的优化,同样可以用在JavaScript中,比如运算结构的调整,这里就不再赘述了。但是由于JavaScript是解释型的,一般不会在运行时对字节码进行优化,所以这些优化仍然是很重要的。当然,其实这里的一些技巧同样使用在其他的一些解释型语言中,大家也可以进行参考。
站在用户的角度思考问题,与客户深入沟通,找到爱民网站设计与爱民网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:做网站、网站制作、企业官网、英文网站、手机端网站、网站推广、空间域名、网站空间、企业邮箱。业务覆盖爱民地区。
避免全局查找
在一个函数中会用到全局对象存储为局部变量来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快些
function search() {
//当我要使用当前页面地址和主机域名
alert(window.location.href + window.location.host);
}
//最好的方式是如下这样 先用一个简单变量保存起来
function search() {
var location = window.location;
alert(location.href + location.host);
}
定时器
如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval,因为setTimeout每一次都会初始化一个定时器,而setInterval只会在开始的时候初始化一个定时器
var timeoutTimes = 0;
function timeout() {
timeoutTimes++;
if (timeoutTimes 10) {
setTimeout(timeout, 10);
}
}
timeout();
//可以替换为:
var intervalTimes = 0;
function interval() {
intervalTimes++;
if (intervalTimes = 10) {
clearInterval(interv);
}
}
var interv = setInterval(interval, 10);
字符串连接
如果要连接多个字符串,应该少使用+=,如
s+=a;
s+=b;
s+=c;
应该写成s+=a + b + c;
而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存,使用JavaScript数组来收集,最后使用join方法连接起来
var buf = [];
for (var i = 0; i 100; i++) {
buf.push(i.toString());
}
var all = buf.join("");
避免with语句
和函数类似 ,with语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度,由于额外的作用域链的查找,在with语句中执行的代码肯定会比外面执行的代码要慢,在能不使用with语句的时候尽量不要使用with语句。
with (a.b.c.d) {
property1 = 1;
property2 = 2;
}
//可以替换为:
var obj = a.b.c.d;
obj.property1 = 1;
obj.property2 = 2;
数字转换成字符串
般最好用”" + 1来将数字转换成字符串,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说:
(“” +) String() .toString() new String()
浮点数转换成整型
很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,我们应该使用Math.floor()或者Math.round()
各种类型转换
var myVar = "3.14159",
str = "" + myVar, // to string
i_int = ~ ~myVar, // to integer
f_float = 1 * myVar, // to float
b_bool = !!myVar, /* to boolean - any string with length
and any number except 0 are true */
array = [myVar]; // to array
如果定义了toString()方法来进行类型转换的话,推荐显式调用toString(),因为内部的操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String,所以直接调用这个方法效率会更高
多个类型声明
在JavaScript中所有变量都可以使用单个var语句来声明,这样就是组合在一起的语句,以减少整个脚本的执行时间,就如上面代码一样,上面代码格式也挺规范,让人一看就明了。
插入迭代器
如var name=values[i]; i++;前面两条语句可以写成var name=values[i++]
使用直接量
var aTest = new Array(); //替换为
var aTest = [];
var aTest = new Object; //替换为
var aTest = {};
var reg = new RegExp(); //替换为
var reg = /../;
//如果要创建具有一些特性的一般对象,也可以使用字面量,如下:
var oFruit = new O;
oFruit.color = "red";
oFruit.name = "apple";
//前面的代码可用对象字面量来改写成这样:
var oFruit = { color: "red", name: "apple" };
使用DocumentFragment优化多次append
一旦需要更新DOM,请考虑使用文档碎片来构建DOM结构,然后再将其添加到现存的文档中。
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
document.body.appendChild(el);
}
//可以替换为:
var frag = document.createDocumentFragment();
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
使用一次innerHTML赋值代替构建dom元素
对于大的DOM更改,使用innerHTML要比使用标准的DOM方法创建同样的DOM结构快得多。
var frag = document.createDocumentFragment();
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
//可以替换为:
var html = [];
for (var i = 0; i 1000; i++) {
html.push('p' + i + '/p');
}
document.body.innerHTML = html.join('');
通过模板元素clone,替代createElement
很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以找一个容器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。通常我们可能会使用字符串直接写HTML来创建节点,其实这样做,1无法保证代码的有效性2字符串操作效率低,所以应该是用document.createElement()方法,而如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,你需要设置多次元素的属性,使用cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元素,应该先准备一个样板节点
var frag = document.createDocumentFragment();
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
//替换为:
var frag = document.createDocumentFragment();
var pEl = document.getElementsByTagName('p')[0];
for (var i = 0; i 1000; i++) {
var el = pEl.cloneNode(false);
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
使用firstChild和nextSibling代替childNodes遍历dom元素
var nodes = element.childNodes;
for (var i = 0, l = nodes.length; i l; i++) {
var node = nodes[i];
//……
}
//可以替换为:
var node = element.firstChild;
while (node) {
//……
node = node.nextSibling;
删除DOM节点
删除dom节点之前,一定要删除注册在该节点上的事件,不管是用observe方式还是用attachEvent方式注册的事件,否则将会产生无法回收的内存。另外,在removeChild和innerHTML=’’二者之间,尽量选择后者. 因为在sIEve(内存泄露监测工具)中监测的结果是用removeChild无法有效地释放dom节点
使用事件代理
任何可以冒泡的事件都不仅仅可以在事件目标上进行处理,目标的任何祖先节点上也能处理,使用这个知识就可以将事件处理程序附加到更高的地方负责多个目标的事件处理,同样,对于内容动态增加并且子节点都需要相同的事件处理函数的情况,可以把事件注册提到父节点上,这样就不需要为每个子节点注册事件监听了。另外,现有的js库都采用observe方式来创建事件监听,其实现上隔离了dom对象和事件处理函数之间的循环引用,所以应该尽量采用这种方式来创建事件监听
重复使用的调用结果,事先保存到局部变量
//避免多次取值的调用开销
var h1 = element1.clientHeight + num1;
var h2 = element1.clientHeight + num2;
//可以替换为:
var eleHeight = element1.clientHeight;
var h1 = eleHeight + num1;
var h2 = eleHeight + num2;
注意NodeList
最小化访问NodeList的次数可以极大的改进脚本的性能
var images = document.getElementsByTagName('img');
for (var i = 0, len = images.length; i len; i++) {
}
编写JavaScript的时候一定要知道何时返回NodeList对象,这样可以最小化对它们的访问
进行了对getElementsByTagName()的调用
获取了元素的childNodes属性
获取了元素的attributes属性
访问了特殊的集合,如document.forms、document.images等等
要了解了当使用NodeList对象时,合理使用会极大的提升代码执行速度
一、网络加载类
1、减少 HTTP 资源请求次数
合并静态资源图片、JavaScript 或 CSS 代码,减少页面请求数和资源请求消耗
避免重复的资源,防止增加多余请求
2、减小 HTTP 请求大小
减少没必要的图片、JavaScript、CSS 及 HTML 代码
对文件进行压缩优化
使用 gzip 等方式压缩传输文件
3将 CSS 或 JavaScript 放到外部文件中,避免使用 style 或 script 标签直接引入
在 HTML 文件中引用外部资源可以有效利用浏览器的静态资源缓存
4、避免页面中空的 href 和 src
当 link 标签的 href 属性为空,或 script、img、iframe 标签的 src 属性为空时,浏览器在渲染的过程中仍会将 href 属性或 src 属性中的空内容进行加载,直至加载失败,这样就阻塞了页面中其他资源的下载进程,而且最终加载到的内容是无效的,因此要尽量避免
5、为 HTML 指定 Cache-Control 或 Expires
为 HTMl 内容设置 CaChe-Control 或 Expires 可以将 HTML 内容缓存起来,避免频繁向服务器端发送请求。
6、合理设置 Etag 和 Last-Modified
合理设置 Etag 和 Last-Modified 使用浏览器缓存,对于未修改的文件,静态资源服务器会向浏览器端返回304,让浏览器从缓存中读取文件,减少 Web 资源下载的带宽消耗并降低服务器负载
7、减少页面重定向
页面每次重定向都会延长页面内容返回的等待延时,一次重定向大约需要600毫秒的时间开销,为了保证用户尽快看到页面内容,要尽量避免页面重定向
8、使用静态资源分域存放来增加下载并行数
浏览器在同一时刻向同一个域名请求文件的并行下载数是有限的,因此可以利用多个域名的主机来存放不同的静态资源,增大页面加载时资源的并行下载数,缩短页面资源加载的时间
9、使用静态资源 CDN 来存储文件
如果条件允许,可以使用 CDN 网络加快同一个地理区域内重复静态资源文件的响应下载速度,缩短资源请求时间
10、使用 CDN Combo 下载传输内容
CDN Combo 是在 CDN 服务器端将多个文件请求打包成一个文件的形式来返回的技术,这样可以实现 HTTP 连接传输的一次性复用,减少浏览器的 HTTP 请求数,加快资源下载速度。
11、使用可缓存的 AJAX
可以返回内容相同的请求,没必要每次都直接从服务器端拉取,合理使用 AJAX 缓存能加快 AJAX 响应速度来减轻服务器压力
12、使用 GET 来完成 AJAX 请求
使用 XMLHttpRequest 时,浏览器中的 POST 方法发送请求首先发送文件头,然后发送 HTTP 正文数据,而使用 GET 时只发送头部,所以在拉取服务端数据时使用 GET 请求效率更高
13、减少 Cookie 的大小并进行 Cookie 隔离
HTTP 请求通常默认带上浏览器的 Cookie 一起发送给服务器,所以在非必要的情况下,要尽量减少 Cookie 来减小 HTTP 请求的大小
对应静态资源,尽量使用不同的域名来存放,因为 Cookie 默认不能跨域的,这样就做到了不同域名下静态资源请求的 Cookie 隔离
14、缩小 favicon.ico 并缓存
有利于 favicon.ico 的重复加载,因为一般一个 Web 应用的 favicon.ico 是很少改变的
15、推荐使用异步 JavaScript 资源
使用 async 时,加载和渲染后续文档元素的过程和 main.js 的加载与执行是并行的。
使用 defer 时,加载后续文档元素的过程和 main.js 的加载是并行的,但是 main.js 的执行要在页面所有元素解析完成之后才开始执行。
16、消除阻塞渲染的 CSS 及 JavaScript
对于页面中加载时间过长的 CSS 或 JavaScript 文件,需要进行合理拆分或延后加载,保证关键路径的资源能快速加载完成
17、避免使用 CSS import 引用加载 CSS
CSS 中的 @import 可以从另一个样式文件引入样式,但应该避免这种用法,因为这样会增加 CSS 资源加载的关键路径长度,带有 @import 的 CSS 样式需要在 CSS 文件串行解析到 @import 时才会加载另外的 CSS 文件,大大延后 CSS 渲染完成的时间
二、页面渲染类
1、把 CSS 资源引用放到 HTML 文件顶部
一般推荐将所有 CSS 资源尽早指定在 HTML 文档 中,这样浏览器可以优先下载 CSS 并尽早完成页面渲染
2、JavaScript 资源引用放到 HTML 文件底部
JavaScript 资源放到 HTML 文档底部可以防止 JavaScript 的加载和解析执行对页面渲染造成阻塞,这是因为 JavaScript 资源默认是解析阻塞的,除非被标记为异步或者通过其他的异步方式加载
3、不要在 HTML 中直接缩放图片
在 HTML 中直接缩放图片会导致页面的重排重绘,此时可能会使页面中的其他操作产生卡顿,因此要尽量减少在页面中直接进行图片缩放
4、减少 DOM 元素数量和深度
HTML 中标签元素越多,标签的层级越深,浏览器解析 DOM 并绘制到浏览器中所花的时间就越长,所以尽可能保持 DOM 元素简洁和层级较少
5、尽量避免使用 table、iframe 等慢元素
table内容的渲染是将 table 的 DOM 渲染树全部生成完成并一次性绘制到页面上的,所以在长表格渲染时很耗性能,应该尽量避免使用它,可以考虑使用列表元素 ul 代替
尽量使用异步的方式动态添加 iframe,因为 iframe 内资源的下载进程会阻塞父页面静态资源的下载与 CSS 及 HTML DOM 的解析
6、避免运行耗时的 JavaScript
长时间运行的 JavaScript 会阻塞浏览器构建 DOM 树、DOM 渲染树、渲染页面。所以,任何与页面初次渲染无关的逻辑功能都应该延迟加载执行,这和 JavaScript 资源的异步加载思路是一致的
7、避免使用 CSS 表达式或 CSS 滤镜
CSS 表达式或 CSS 滤镜的解析渲染速度是比较慢的,在有其他解决方案的情况下应该尽量避免使用
前言
一直在学习javascript,也有看过《犀利开发Jquery内核详解与实践》,对这本书的评价只有两个字犀利,可能是对javascript理解的还不够透彻异或是自己太笨,更多的是自己不擅于思考懒得思考以至于里面说的一些精髓都没有太深入的理解。
鉴于想让自己有一个提升,进不了一个更加广阔的天地,总得找一个属于自己的居所好好生存,所以平时会有意无意的去积累一些使用jQuerry的常用知识,特别是对于性能要求这一块,总是会想是不是有更好的方式来实现。
下面是我总结的一些小技巧,仅供参考。(我先会说一个总标题,然后用一小段话来说明这个意思 再最后用一个demo来简单言明)
避免全局查找
在一个函数中会用到全局对象存储为局部变量来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快些
function search() {
//当我要使用当前页面地址和主机域名
alert(window.location.href + window.location.host);
}
//最好的方式是如下这样 先用一个简单变量保存起来
function search() {
var location = window.location;
alert(location.href + location.host);
}
定时器
如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval,因为setTimeout每一次都会初始化一个定时器,而setInterval只会在开始的时候初始化一个定时器
var timeoutTimes = 0;
function timeout() {
timeoutTimes++;
if (timeoutTimes 10) {
setTimeout(timeout, 10);
}
}
timeout();
//可以替换为:
var intervalTimes = 0;
function interval() {
intervalTimes++;
if (intervalTimes = 10) {
clearInterval(interv);
}
}
var interv = setInterval(interval, 10);
字符串连接
如果要连接多个字符串,应该少使用+=,如
s+=a;
s+=b;
s+=c;
应该写成s+=a + b + c;
而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存,使用JavaScript数组来收集,最后使用join方法连接起来
var buf = [];
for (var i = 0; i 100; i++) {
buf.push(i.toString());
}
var all = buf.join("");
避免with语句
和函数类似 ,with语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度,由于额外的作用域链的查找,在with语句中执行的代码肯定会比外面执行的代码要慢,在能不使用with语句的时候尽量不要使用with语句。
with (a.b.c.d) {
property1 = 1;
property2 = 2;
}
//可以替换为:
var obj = a.b.c.d;
obj.property1 = 1;
obj.property2 = 2;
数字转换成字符串
般最好用”" + 1来将数字转换成字符串,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说:
(“” +) String() .toString() new String()
浮点数转换成整型
很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,我们应该使用Math.floor()或者Math.round()
各种类型转换
var myVar = "3.14159",
str = "" + myVar, // to string
i_int = ~ ~myVar, // to integer
f_float = 1 * myVar, // to float
b_bool = !!myVar, /* to boolean - any string with length
and any number except 0 are true */
array = [myVar]; // to array
如果定义了toString()方法来进行类型转换的话,推荐显式调用toString(),因为内部的操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String,所以直接调用这个方法效率会更高
多个类型声明
在JavaScript中所有变量都可以使用单个var语句来声明,这样就是组合在一起的语句,以减少整个脚本的执行时间,就如上面代码一样,上面代码格式也挺规范,让人一看就明了。
插入迭代器
如var name=values[i]; i++;前面两条语句可以写成var name=values[i++]
使用直接量
var aTest = new Array(); //替换为
var aTest = [];
var aTest = new Object; //替换为
var aTest = {};
var reg = new RegExp(); //替换为
var reg = /../;
//如果要创建具有一些特性的一般对象,也可以使用字面量,如下:
var oFruit = new O;
oFruit.color = "red";
oFruit.name = "apple";
//前面的代码可用对象字面量来改写成这样:
var oFruit = { color: "red", name: "apple" };
使用DocumentFragment优化多次append
一旦需要更新DOM,请考虑使用文档碎片来构建DOM结构,然后再将其添加到现存的文档中。
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
document.body.appendChild(el);
}
//可以替换为:
var frag = document.createDocumentFragment();
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
使用一次innerHTML赋值代替构建dom元素
对于大的DOM更改,使用innerHTML要比使用标准的DOM方法创建同样的DOM结构快得多。
var frag = document.createDocumentFragment();
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
//可以替换为:
var html = [];
for (var i = 0; i 1000; i++) {
html.push('p' + i + '/p');
}
document.body.innerHTML = html.join('');
通过模板元素clone,替代createElement
很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以找
一个容器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。通常我们可能会使用字符串直接写
HTML来创建节点,其实这样做,1无法保证代码的有效性2字符串操作效率低,所以应该是用document.createElement()方法,而如
果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,你需要设置多次元素的属性,使用
cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元素,应该先准备一个样板节点
var frag = document.createDocumentFragment();
for (var i = 0; i 1000; i++) {
var el = document.createElement('p');
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
//替换为:
var frag = document.createDocumentFragment();
var pEl = document.getElementsByTagName('p')[0];
for (var i = 0; i 1000; i++) {
var el = pEl.cloneNode(false);
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag);
使用firstChild和nextSibling代替childNodes遍历dom元素
var nodes = element.childNodes;
for (var i = 0, l = nodes.length; i l; i++) {
var node = nodes[i];
//……
}
//可以替换为:
var node = element.firstChild;
while (node) {
//……
node = node.nextSibling;
类型转换 类型转换是大家常犯的错误,因为JavaScript是动态类型语言,你不能指定变量的类型。 1. 把数字转换成字符串,应用"" + 1,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说:("" +) String() .toString() new String()这条其实和下面的“直接量”有点类似,尽量使用编译时就能使用的内部操作要比运行时使用的用户操作要快。String()属于内部函数,所以速度很快,而.toString()要查询原型中的函数,所以速度逊色一些,new String()用于返回一个精确的副本。 2. 浮点数转换成整型,这个更容易出错,很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,我们应该使用Math.floor()或者Math.round()。另外,和第二节的对象查找中的问题不一样,Math是内部对象,所以Math.floor()其实并没有多少查询方法和调用的时间,速度是最快的。 3. 对于自定义的对象,如果定义了toString()方法来进行类型转换的话,推荐显式调用toString(),因为内部的操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String,所以直接调用这个方法效率会更高 使用直接量 其实这个影响倒比较小,可以忽略。什么叫使用直接量,比如,JavaScript支持使用[param,param,param,...]来直接表达一个数组,以往我们都使用new Array(param,param,...),使用前者是引擎直接解释的,后者要调用一个Array内部构造器,所以要略微快一点点。 同样,var foo = {}的方式也比var foo = new Object();快,var reg = /../;要比var reg=new RegExp()快。 字符串遍历操作 对字符串进行循环操作,譬如替换、查找,应使用正则表达式,因为本身JavaScript的循环速度就比较慢,而正则表达式的操作是用C写成的语言的API,性能很好。 高级对象 自定义高级对象和Date、RegExp对象在构造时都会消耗大量时间。如果可以复用,应采用缓存的方式。DOM相关 插入HTML 很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以找一个容器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。 对象查询 使用[“”]查询要比.items()更快,这和前面的减少对象查找的思路是一样的,调用.items()增加了一次查询和函数的调用。 创建DOM节点 通常我们可能会使用字符串直接写HTML来创建节点,其实这样做无法保证代码的有效性字符串操作效率低,所以应该是用document.createElement()方法,而如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用createElement()方法之后,你需要设置多次元素的属性,使用cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元素,应该先准备一个样板节点。 定时器 如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval。setTimeout每次要重新设置一个定时器。