一.Javascript代码执行效率
1. DOM
1.1 使用 DocumentFragment 优化多次 append
说明:添加多个 dom 元素时,先将元素 append 到 DocumentFragment 中,最后统一将 DocumentFragment 添加到页面。
该做法可以减少页面渲染 dom 元素的次数。经 IE 和 Fx 下测试,在 append1000 个元素时,效率能提高 10%-30% , Fx 下提升较为明显。
服用前:
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);
1.2 通过模板元素 clone ,替代 createElement
说明:通过一个模板 dom 对象 cloneNode ,效率比直接创建 element 高。性能提高不明显,约为 10% 左右。在低于 100 个元素 create 和 append 操作时,没有优势。
服用前:
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);
1.3 使用一次 innerHTML 赋值代替构建 dom 元素
说明:根据数据构建列表样式的时候,使用设置列表容器 innerHTML 的方式,比构建 dom 元素并 append 到页面中的方式,效率有数量级上的提高。
服用前:
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('
' + i + '
');
}
document.body.innerHTML = html.join('');

1.4 使用 firstChild 和 nextSibling 代替 childNodes 遍历 dom 元素

说明:约能获得 30%-50% 的性能提高。逆向遍历时使用 lastChild 和 previousSibling 。
服用前:
var nodes = element.childNodes;
for (var i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i];
……
}

服用后:

var node = element.firstChild;
while (node) {
……
nodenode = node.nextSibling;
}

2. 字符串

2.1 使用 Array 做为 StringBuffer ,代替字符串拼接的操作 
说明: IE 在对字符串拼接的时候,会创建临时的 String 对象;经测试,在 IE 下,当拼接的字符串越来越大时,运行效率会急剧下降。 Fx 和 Opera 都 对字符串拼接操作进行了优化;经测试,在 Fx 下,使用 Array 的 join 方式执行时间约为直接字符串拼接的 1.4 倍。
服用前:
var now = new Date();
var str = '';
for (var i = 0; i < 10000; i++) {
str += '123456789123456789';
}
alert(new Date() - now);

服用后:

var now = new Date();
var strBuffer = [];
for (var i = 0; i < 10000; i++) {
strBuffer.push('123456789123456789');
}
var str = strBuffer.join('');
alert(new Date() - now);

3. 循环语句

3.1 将循环控制量保存到局部变量
说明:对数组和列表对象的遍历时,提前将 length 保存到局部变量中,避免在循环的每一步重复取值。
服用前:
var list = document.getElementsByTagName('p');
for (var i = 0; i < list.length; i++) {
……
}

服用后:

var list = document.getElementsByTagName('p');
for (var i = 0, l = list.length; i < l; i++) {
……
}

3.2 顺序无关的遍历时,用 while 替代 for

说明:该方法可以减少局部变量的使用。比起效率优化,更能直接看到的是字符数量的优化。该做法有程序员强迫症的嫌疑。
服用前:
var arr = [1,2,3,4,5,6,7];
var sum = 0;
for (var i = 0, l = arr.length; i < l; i++) {
sum += arr[i];
}

服用后:

var arr = [1,2,3,4,5,6,7];
var sum = 0, l = arr.length;
while (l--) {
sum += arr[l];
}

4. 条件分支

4.1 将条件分支,按可能性顺序从高到低排列
说明:可以减少解释器对条件的探测次数。
4.2 在同一条件子的多( >2 )条件分支时,使用 switch 优于 if
说明: switch 分支选择的效率高于 if ,在 IE 下尤为明显。 4 分支的测试, IE 下 switch 的执行时间约为 if 的一半。
4.3 使用三目运算符替代条件分支
服用前:
if (a > b) {
num = a;
} else {
num = b;
}
服用后: 
num = a > b ? a : b;
5. 定时器
5.1 需要不断执行的时候,优先考虑使用 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);

5.2 使用 function 而不是 string

说明:如果把字符串作为 setTimeout 和 setInterval 的参数,浏览器会先用这个字符串构建一个 function 。
服用前:
var num = 0;
setTimeout('num++', 10);

服用后:

var num = 0;
function addNum () {
num++;
}
setTimeout(addNum, 10);

6. 其他

6.1 尽量不使用动态语法元素
说明: eval 、 Function 、 execScript 等语句会再次使用 javascript 解析引擎进行解析,需要消耗大量的执行时间。
6.2 重复使用的调用结果,事先保存到局部变量
说明:避免多次取值的调用开销。
服用前:
var h1 = element1.clientHeight + num1;
var h2 = element1.clientHeight + num2;

服用后:

var eleHeight = element1.clientHeight;
var h1 = eleHeight + num1;
var h2 = eleHeight + num2;

6.3 使用直接量

说明:
var a = new Array(param,param,...) -> var a = []
var foo = new Object() -> var foo = {}
var reg = new RegExp() -> var reg = /.../

6.4 避免使用 with

说明: with 虽然可以缩短代码量,但是会在运行时构造一个新的 scope 。 
OperaDev 上还有这样的解释,使用 with 语句会使得解释器无法在语法解析阶段对代码进行优化。对此说法,无法验证。
服用前:
with (a.b.c.d) {
property1 = 1;
property2 = 2;
}

服用后:

var obj = a.b.c.d;
obj.property1 = 1;
obj.property2 = 2;

6.5 巧用 || 和 && 布尔运算符

重要程度: ★★★
服用前:
function eventHandler (e) {
if(!e) e = window.event;
}

服用后:

function eventHandler (e) {
ee = e || window.event;
}

服用前:

if (myobj) {
doSomething(myobj);
}

服用后:

myobj && doSomething(myobj);

6.6 类型转换

说明:
1). 数字转换成字符串,应用 "" + 1 ,性能上: ("" +) > String() > .toString() > new String() ;
2). 浮点数转换成整型,不使用 parseInt() , parseInt() 是用于将字符串转换成数字,而不是浮点数和整型之间的转换,建议使用 Math.floor() 或者 Math.round()
3). 对于自定义的对象,推荐显式调用 toString() 。内部操作在尝试所有可能性之后,会尝试对象的 toString() 方法尝试能否转化为 String 。
二.内存管理
2.1 循环引用
说明:如果循环引用中包含 DOM 对象或者 ActiveX 对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。
简单的循环引用:
var el = document.getElementById('MyElement');
var func = function () {…}
el.func = func;
func.element = el;

但是通常不会出现这种情况。通常循环引用发生在为 dom 元素添加闭包作为 expendo 的时候。

如:
function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {……}
}
init();

init 在执行的时候,当前上下文我们叫做 context 。这个时候, context 引用了 el , el 引用了 function , function 引用了 context 。这时候形成了一个循环引用。

下面 2 种方法可以解决循环引用:
1) 置空 dom 对象
服用前:
function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {……}
}
init();

服用后:

function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {……}
el = null;
}
init();

将 el 置空, context 中不包含对 dom 对象的引用,从而打断循环应用。

如果我们需要将 dom 对象返回,可以用如下方法:
服用前:
function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {……}
return el;
}
init();

服用后:

function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {……}
try{
return el;
} finally {
el = null;
}
}
init();

2) 构造新的 context

服用前:
function init() {
var el = document.getElementById('MyElement');
el.onclick = function () {……}
}
init();

服用后:

function elClickHandler() {……}
function init() {
var el = document.getElementById('MyElement');
el.onclick = elClickHandler;
}
init();

把 function 抽到新的 context 中,这样, function 的 context 就不包含对 el 的引用,从而打断循环引用。

2.2 通过 javascript 创建的 dom 对象,必须 append 到页面中
说明: IE 下,脚本创建的 dom 对象,如果没有 append 到页面中,刷新页面,这部分内存是不会回收的!
示例代码:
function create () {
var gc = document.getElementById('GC');
for (var i = 0; i < 5000 ; i++)
{
var el = document.createElement('div');
el.innerHTML = "test";

// 下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化

gc.appendChild(el);
}
}

2.3 释放 dom 元素占用的内存

说明: 
将 dom 元素的 innerHTML 设置为空字符串,可以释放其子元素占用的内存。
在 rich 应用中,用户也许会在一个页面上停留很长时间,可以使用该方法释放积累得越来越多的 dom 元素使用的内存。
2.4 释放 javascript 对象
说明:在 rich 应用中,随着实例化对象数量的增加,内存消耗会越来越大。所以应当及时释放对对象的引用,让 GC 能够回收这些内存控件。
对象: obj = null
对象属性: delete obj.myproperty
数组 item :使用数组的 splice 方法释放数组中不用的 item
2.5 避免 string 的隐式装箱
说明:对 string 的方法调用,比如 'xxx'.length ,浏览器会进行一个隐式的装箱操作,将字符串先转换成一个 String 对象。推荐对声明有可能使用 String 实例方法的字符串时,采用如下写法:
var myString = new String('Hello World');

如何编写高性能的 javascript的更多相关文章

  1. 编写高性能的javascript代码(持续更新)

    参考资料: Vanilla JS——世界上最轻量的JavaScript框架(没有之一) http://segmentfault.com/a/1190000000355277 探索高效jQuery的奥秘 ...

  2. 编写高性能Javascript代码的若干建议

    多年来,Javascript一直在web应用开发中占据重要的地位,但是很多开发者往往忽视一些性能方面的知识,特别是随着计算机硬件的不断升级,开发者越发觉得Javascript性能优化的好不好对网页的执 ...

  3. 编写高性能Javascript

    编写高性能Javascript 多年来,Javascript一直在web应用开发中占据重要的地位,但是很多开发者往往忽视一些性能方面的知识,特别是随着计算机硬件的不断升级,开发者越发觉得Javascr ...

  4. 【JavaScript】【译】编写高性能JavaScript

    英文链接:Writing Fast, Memory-Efficient JavaScript 很多JavaScript引擎,如Google的V8引擎(被Chrome和Node所用),是专门为需要快速执 ...

  5. 编写高性能JavaScript【转】

    英文链接:Writing Fast, Memory-Efficient JavaScript 很多JavaScript引擎,如Google的V8引擎(被Chrome和Node所用),是专门为需要快速执 ...

  6. 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点

    深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 2011-12-28 23:00 by 汤姆大叔, 139489 阅读, 119 评论, 收藏, 编辑 才华横溢的 ...

  7. 编写高性能Web应用程序的10个技巧

    这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...

  8. 高性能的JavaScript -- 读书笔记

    高性能的JavaScript 一.      加载和运行 将脚本放在底部 脚本下载解析执行时,页面已经加载完成并显示在用户面前 成组脚本 减少外部脚本文件数量,整合成一个文件 延迟脚本 动态脚本元素 ...

  9. 编写高性能 Web 应用程序的 10 个技巧

    使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信.正因为如此简单,所以很多开发人员就不会花时间来设计其应用程序的结构,以获得更好的性能了.在本文中,我将讲述 10 个用于编写高性能 ...

随机推荐

  1. [CSP-S模拟测试]:x(数学+并查集)

    题目背景 $\frac{1}{4}$遇到了一道水题,叒完全不会做,于是去请教小$D$.小$D$都没看就切掉了这题,嘲讽了$\frac{1}{4}$一番就离开了.于是,$\frac{1}{4}$只好来问 ...

  2. [CSP-S模拟测试]:Lost My Music(凸包)

    题目描述 小$w$在天堂看到了一棵世界树.世界树上有$n$个节点,其中$1$节点为根,每个节点有一个正整数权值$c_i$.现在小$w$想要对每个节点$u$求出它的祖先$v$中$\frac{c_v-c_ ...

  3. 转载:解决npm安装时出现run `npm audit fix` to fix them, or `npm audit` for details

    转载自:https://blog.csdn.net/qq_39165556/article/details/89333028 1.第一种解决办法 npm audit fix npm audit fix ...

  4. python中递归函数

    python中的 递归函数,是指的是函数在函数内部调用自己的函数 需要满足两个条件,一,需要有一个明确的终止条件 二,需要函数自己在内部调用自己

  5. vs2005安装 和 Fatal Error C1902

    win10系统不能激活 win7可以激活,运行会出现兼容错误,解决办法装2个sp1补丁 拷贝mspdb80.dll到系统目录后会出现 Fatal Error C1902, 解决方法如下: VC++20 ...

  6. <读书笔记>《React:引领未来的用户界面开发框架》

    <React:引领未来的用户界面开发框架>(GitHub 附demo版) 1.Component的创建与复合 1.1 React简介 背景介绍,全书概览 1.本质上是一个状态机,它以精简的 ...

  7. CPU的架构:x86、arm、mips、龙芯等

    在公司经常听其他工程师讲x86,arm平台啥的,作为一个算法工程师,我听过却不知道这是啥!!!(汗颜) 现在偷偷学起: x86,arm,mips等这些都是CPU的架构,不管是手机电脑还是一些嵌入式的设 ...

  8. git笔记十:本地仓库同步到gitlab

    本地仓库同步到gitlab 帮助文档 git remote --help 操作场景: 本地创建git仓库(含有readme.md文件), commit了三次 gitlab网站创建了一个项目 添加了re ...

  9. Gentoo 搭遗

    安装 app-portage/gentoolkit 使用如下方式,可查询某个被包安装的文件列表,可以筛选文件类型 equey files [--filter=doc] <包名称> emer ...

  10. gitlab fatal: Authentication failed for 'http://10.2.80.17:8090/yeyichao/201904041026PROj.git/'

    fatal: Authentication failed for 'http://10.2.80.17:8090/yeyichao/201904041026PROj.git/' git config ...