一、脚本的加载和运行的阻塞性能优化
script标签的出现,每次都需要让页面等待下载,解析,执行,如果把script写在head标签里面,页面的下载和渲染都需要等待脚本执行完毕。虽说目前的大多浏览器都都有并发请求加载的机制,但是script脚本的解析和运行依旧是阻塞页面内容加载和交互的一个问题。
待优化的案例脚本:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>script</title>
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="file3.js"></script>
</head>
<body>
<p>Hello script!</p>
</body>
</html>
优化方案一
将多个脚本压缩合并放在一个脚本里面,且将该脚本放置在页面底部
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>script</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<p>Hello script!</p>
<!-- 放置在此处 -->
<script type="text/javascript" src="all.js"></script>
</body>
</html>
优化方案二 (无阻塞延迟脚本)
(1)给script标签添加defer、async属性
- 给script标签添加defer属性,在页面加载完成后,在onload事件触发前执行该脚本
- 给script标签添加async属性,标志着在脚本异步加载完成后,执行。并非是在页面加载完后执行
(2)动态脚本下载且执行代码,类似于CMD规范的require
A. H5浏览器通用版
function loadScript(url, calllback){
let script = document.createElement('script');
script.src = url;
script.onload = function(){
cakkback();
}
document.head.appendChild(script);
}
B. 兼容浏览器版(IE)
function loadScript(url, calllback){
let script = document.createElement('script');
script.type = 'text/javascript'
script.src = url;
// IE
if(script.readyState){
script.onreadystatechange = function(){
if(script.readyState == 'loaded' || script.readyState == 'complete'){ //兼容多版本IE
script.onreadystatechange = null;
callback();
}
}
}else{
script.onload = function(){
cakkback();
}
}
document.head.appendChild(script);
}
使用方法:
loadScript('file.js',function(){
// 执行
})
注:类似相关库推荐YUI3、LazyLoad、LABjs
(3)使用ajax请求来异步加载文件内容,并生成script脚本,注入页面中
function loadScript(url,callback){
fetch(url).then(res => res.text()).then(res => {
let script = document.createElement('script');
script.text = res;
document.body.appendChild(script);
})
}
结论
最优方式是采用的是动态脚本加载方式
二、数据存取性能优化
Javascript中数据存储的位置会对代码整体产生重大的影响,且数据存储的四种方式:字面量、变量、数据项、对象成员
1.访问字面量和局部变量最快,访问数组和对象相对较慢
2.局部变量存储在作用域链的起始位置,因此访问局部变量比访问全局变量要快很多,变量处在作用域链的位置越深(越接近全局),访问越慢。由于全局变量处于作用域的最末端,所以访问也是最慢的。
3.避免使用with语句,因为它会改变执行环境的作用域链。同样,try-catch语句中的catch子句也有同样的作用,使用也应该慎重。
(1)with语句的使用案例
function renderDOM(){
with(document){
let bd = body,link = getElementsByRagName('a'),i = 0,len = links.length;
while(i < len){
update(links[i++])
}
getElementById('go-btn').onclick = function(){
start();
}
bd.className = 'active';
}
}
(2)try-catch语句
try{
methodCauseError();
}catch(exp){
handleError(exp); // 委托给从错误处理函数 从下一行开始作用域改变
}
4.嵌套的对象成员会很明显的性能影响,尽可能少用
5.属性和方法在原型链的位置越深,访问它的速度就会越慢
6.把常用的对象成员、数组成员、外部变量保存在局部变量中,可以改善js的性能,因为局部访问速度也会更快