前端工作离不开性能优化,关于前端优化可以分为以下维度。
加载和执行
管理JavaScript代码是个棘手的问题,代码在执行过程中会阻塞浏览器的其它进程,如用户界面绘制。每遇到<script>标签,页面就必须停下来等待代码的下载(外链文件)并执行,然后继续处理其它部分。从JS加载和执行的原理由以下几种方法来提升性能。
- </body>闭合标签前,将所有的<script>标签放到页面底部。这样确保了脚本执行前页面已经完成渲染。
- 合并脚本。页面中的<script>标签越少,响应也更迅速。无论外链文件还是内链文件都如此。以此减少HTTP请求次数。
- 多种无阻塞下载JavaScript的方法
- 用<script> 标签的defer属性(外链【根据W3C的HTML5规范定义:defer属性仅当src属性声明时才有效】)
<script src="common/a.js" defer></script>
- 使用动态创建的script元素来下载并执行代码
function loadScript(url, callback) {
var script = document.createElement("script");
script.type = "text/javascript";
if (script.readyState) {
script.onreadystatechange = function () {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
}
} else {
script.onload = function () {
callback();
}
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
还有其它开源无阻塞脚本加载工具:lazyload.js 、lab.js等
- 使用XHR对象下载JavaScript代码并注入页面
var xhr = new XMLHttpRequest();
xhr.open("get", "a.js", true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
var script = document.createElement("script");
script.type = "text/javascript";
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
}
数据存取
数据存储共有4种方式:字面量、变量、数组项(元素以数字为索引)、对象成员(键值对以key为索引),它们由各自的性能特点。
- 访问字面量和变量的速度最快,相反,访问数组元素和对象成员相对较慢
- 由于局部变量存在与原型链的最起始位置,因此访问局部变量比访问作用域变量更块。变量在作用域中的位置越深,访问所需要的时间就越长,由于全局变量总处在作用域的最末端,因为访问也最慢。
- 避免使用with语句,因为它会改变执行环境作用域链。同样try-catch语句中的catch字句也有同样的影响,因此要小心使用。
- 嵌套的对象成员会明显影响性能,尽量少用。
- 属性或方法在原型链中的位置越深,访问它的速度越慢。
- 通常来说,我们可以把常用的对象成员、数组元素、跨域变量保存在局部变量中来改善JavaScript性能,因为局部变量访问速度更快。
Dom操作编程
访问和操作Dom是Web应用的重要部分。但每次穿越连接ECMSScript和Dom两个岛屿之间的桥梁,都会被收取“过桥费”。为了减少Dom编程带来的性能损失,有以下几点优化方法:
- 最小化Dom访问次数,尽可能在JavaScript端处理
- 如果需要多次访问某个Dom节点,请使用局部变量存储它的引用。
- 小心处理HTML集合,因为它实时连接着底层文档。把集合的长度缓存到一个变量中,并在迭代中使用它。如果需要经常操作集合,把它拷贝到一个数组中
- 如果可能的话,使用速度更快的API如querySelectorAll和firstElementChild。
- 要留意重绘和重排;批量修改样式时,“离线”操作Dom树,使用缓存,并减少访问局部信息的次数。
- 动画中使用绝对定位,使用拖放代理。
- 使用事件委托来减少处理器的数量。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
.menu_ul li {
height: 30px;
/*list-style-type: none;*/
}
</style>
</head>
<body>
<div>
<ul class="menu_ul">
<li>
<a href="m1.html">menu #1</a>
</li>
<li>
<a href="m2.html">menu #2</a>
</li>
<li>
<a href="m3.html">menu #3</a>
</li>
<li>
<a href="m4.html">menu #4</a>
</li>
<li>
<a href="m5.html">menu #5</a>
</li>
</ul>
</div>
<script>
document.getElementsByClassName('menu_ul')[0].onclick = function (e) {
e = e || window.event;
var target = e.target || e.srcElement;
if (target.nodeName !== 'A') {
console.log("no a ")
return;
}
console.log(e.target)
var hrefParts = target.href.split('/')
var pageId = hrefParts[hrefParts.length - 1];
pageId = pageId.replace(".html", '');
console.log(pageId);
if (e.preventDefault === 'function') {
e.preventDefault();
e.stopPropagation();
} else {
e.returnValue = false;
e.cancelBubble = true;
}
}
</script>
</body>
</html>
网友评论