文章内容输出来源:拉勾大前端高薪训练营
1、性能测试工具 JSBench 使用
网址:https://jsbench.me/ 常用的 JSperf 已经停止维护了
- Setup HTML 想初始化的dom
- Setup JS 前置统一的js代码
- Test Case 添加测试用例,具体的测试代码(一般两个)
- Teardown JS 后置统一的js代码
(每秒的次数 越大越好)
性能测试细节:尽可能开一个标签页、当前的进程不要关掉、多次执行
2、堆栈中代码执行流程
- 首先堆内存中创建执行环境栈,执行环境栈中存放不同的执行上下文
- 代码从上往下之下,先创建全局上下文,
- 基本数据类型值存在栈内存中,由JS主线程管理,
引用类型存放在堆内存中,一般由GC回收处理 - 每当遇到函数执行,重新生成执行上下文进栈,
代码执行完,由是否产生闭包决定我们当前的上下文中引用的堆要不要被释放掉
let a = 10;
function foo(b){
let a = 2;
function baz(c){
console.log(a+b+c);
}
return baz;
}
let fn = foo(2);
fn(3);
ECStack 执行环境栈:
EC(baz执行上下文)
this = window
<baz.ao, foo.ao, vo>
AO:
arguments:{0: 3}
c = 3
console.log(a + b + c)
3 + 2 + 1 = 7
EC(foo执行上下文)
this = window
<foo.ao, vo> // foo.ao代表自己的作用域
AO:
arguments:{0: 2}
a = 2
baz = AB2 [[scope]] foo.AO
EC(全局执行上下文)
VO:
a = 10 (字面量直接存在栈中)
foo = AB1 [[scope]] VO
fn = AB2
堆内存: AB1
function foo(b){...}
name: foo
length: 1
堆内存: AB2
function baz(c){...}
name: baz
length: 1
3、减少判断层级
function doSomething(part, chapter){
const parts = ['ES2016', '工程化', 'Vue', 'React', 'Node'];
if(part){
if(parts.includes(part)){
console.log('属于当前课程')
if(chapter > 5){
console.log('您需要提供VIP身份')
}
}
}else{
console.log('请确定模块信息')
}
}
doSomething('ES2016', 6);
//优化后
function doSomething(part, chapter){
const parts = ['ES2016', '工程化', 'Vue', 'React', 'Node'];
if(!part){
console.log('请确定模块信息');
return
}
if(!parts.includes(part)) return
console.log('属于当前课程')
if(chapter > 5){
console.log('您需要提供VIP身份')
}
}
4、减少作用域链查找层级
避免全局查找
全局查找相关
- 目标变量不存在于当前作用内,通过作用域链向上查找
- 减少全局查找降低实践消耗
- 减少不必要的全局变量定义
- 全局变量数据局部化
var name = 'zce';
function foo(){
//name = 'zce666'; //这里的name 是属于全局的
//优化
var name = 'zce666';
function baz(){
var age = 18;
console.log(age);
console.log(name)
}
baz();
}
foo();
//快建立在内存空间消耗上
5、减少数据读取次数
//html
<div id="skip" class="skip"></div>
var oBox = document.getElementById('skip');
function hasEle(ele, cls){
return ele.className == cls;
}
console.log(hasEle(oBox, 'skip'));
//优化
function hasEle(ele, cls){
var className = ele.className
return className == cls;
}
//快建立在内存空间消耗上
6、字面量与构造式
用字面量比构造式执行效率高
var test = () => {
let obj = new Object();
obj.name = 'sz';
obg.age = 18;
return obj;
}
console.log(test());
//字面量
var test = () => {
let obj = {
name: 'sz',
age: 18
}
return obj;
}
console.log(test());
//示例二
var str1 = '你好呀'; //字符串
var str2 = new String('你好呀'); //对象
console.log(str1);
console.log(str2);
7、减少循环体中活动
避免循环引用
- 全局引用指多个对象间存在互相引用
- 采用字面量替换New操作
- setTimeout 替换 setInterval
- 采用事件委托
- 合并循环变量和条件
var test = () => {
var i
var arr = ['zce', 18, '你好呀'];
for(i = 0; i < arr.length; i++){
console.log(arr[i])
}
}
test();
//优化后
var test = () => {
var i
var arr = ['zce', 18, '你好呀'];
var len = arr.length;
for(i = 0; i < len; i++){
console.log(arr[i])
}
}
//再优化
var test = () => {
var arr = ['zce', 18, '你好呀'];
var len = arr.length;
while(len--){
console.log(arr[len]);
}
}
8、减少声明及语句数
//html
<div id="box" style="width: 100px; height: 100px;"></div>
var oBox = document.getElementById('box');
var test = (ele) => {
let w = ele.offsetWidth;
let h = ele.offsetHeight
return w * h;
}
//优化后
var test = (ele) => {
return ele.offsetWidth * ele.offsetHeight;
}
console.log(test(oBox));
//示例2
var test = () => {
var name = 'zc';
var age = 18;
return name + age;
}
var test = () => {
var name = 'sc',
age = 18;
return name + age;
}
console.log(test())
9、采用事件委托
子元素的事件 委托给 父元素来完成
//html
<ul id="ul">
<li>ZC</li>
<li>18</li>
</ul>
var list = document.querySelectorAll('li');
function showTxt(ev){
console.log(ev.target.innerHTML);
}
for(let item of list){
item.onclick = showTxt;
}
//优化
var oUl = document.getElementById('ul');
oUl.addEventListener('click', showTxt, true);
function showTxt(ev){
var obj = ev.target;
if(obj.nodeName.toLowerCase() === 'li'){
console.log(obj.innerHTML);
}
}